Is It a Good Way to Access Instance Variable with Self? If I Use a Lot

Using self-ivar when accessing instance variables directly

Chuck is correct in that there's no technical reason you shouldn't write it that way, unless you're shadowing ivars with local variables, which is is generally a bad idea. However, it's arguable that omitting self-> is stylistically cleaner, and it certainly results in less verbose code. Personally I would find the self-> to be distracting (especially if the code is well-designed and variables are well-named) but if it makes things more understandable for you, by all means do it. Just be aware that if you show your code to other Objective-C programmers, they're likely to have a conflicting opinion, so it's good to have a think skin. Besides, most programmers find that their perception of what makes code "feel good" changes over time and with experience, and those opinions often mellow out with age. :-)

Is it better to use self variable than pass variable in a class?

In Python, you have a lot of freedom to do what "makes sense". In this case, I would say that it depends on how you plan on using func2 and who will be accessing it. If func2 is only ever supposed to act upon self.var, then you should code it as such. If other objects are going to need to pass in different arguments to func2, then you should allow for it to be an argument. Of course, this all depends on the larger scope of what you're trying to do, but given your simple example, this makes sense.

Also, I'm confused about how your question relates to global variables. Member variables are not the same thing as global variables.

Edited to reflect updated post:

The difference between A and B in your example is that B persists the information about self.var, while A does not. If var needs to be persisted as part of the object's state, then you need to store it as part of self. I get the sense that your question might relate more to objects as a general concept than anything Python-specific.

Understanding the self keyword when referring to a class instance variable in a ruby?

tl;dr: foo = value will always refer to a local variable foo not the method call self.foo=(value).


I am assumed this is because I need the self keyword to refer to the instance variable, total

No, total is a local variable, not an instance variable. @total is an instance variable. A local variable lives for the current scope, like a single method call. An instance variable sticks with the object.

You need the self keyword to refer to the method total=. Let's dive in.

attr_accessor :total declares two methods, total and total=. These are wrappers to get and set the instance variable @total. The following code does the equivalent.

def total
@total
end

def total=(value)
@total = value
end

Note that the method is named total=, this will become important in a moment.

With that in mind, let's look at your code.

def add(amount)
self.total = self.total + amount
end

(Almost) everything in Ruby is really a method call. The above is syntax sugar for calling the total= method on self.

def add(amount)
self.total=(self.total + amount)
end

Now what happens if we remove self like so?

def add(amount)
total = total + amount
end

In Ruby, self is optional. Ruby will figure out if total means the method total or the local variable total. The local variable takes precedence and assignment is always to a local variable.

total = total + amount works like so:

def add(amount)
total = self.total + amount
end

Assignment is always to a local variable.

To further illustrate, what if we declared total first?

def add(amount)
total = 23
self.total = total + amount
end

The existing local variable total takes precedence over the total() method. total + amount refers to the local variable total and so cr.add(10); puts cr.total will be 33.


total = ... will always refer to the local variable total. For this reason if you want to use method assignment you must explicitly use self.total=. In other cases you can drop the self. And avoid local variables with the same name as methods.

def add(amount)
# self.total = self.total + amount
self.total = total + amount
end

Why did I not need self in add_student?

Because there is no ambiguity. You're not assigning to a local variable roster.

def add_student(student, grade)
roster[grade] = roster[grade] || []
roster[grade] << student
end

roster[grade] is really self.roster.[]=(grade). You are calling self.roster which returns a Hash and then calling the []= method on that Hash to give it a new key/value pair.

Similarly, roster[grade] << student is self.roster.[](grade).<<(student). Get aHash, call [[]](https://ruby-doc.org/core/Hash.html#method-i-5B-5D) on it to retrieve theArrayand call [<<](https://ruby-doc.org/core/Array.html#method-i-3C-3C) on thatArray`.

def add_student(student, grade)
self.roster.[]=(grade) = self.roster.[](grade) || []
self.roster.[](grade).<<(student)
end

Yes, [], []=, and << are all methods names like any other.


A lot of Ruby mysteries go away once you understand the method calls under the syntax sugar and that things like [], []=, << and so on are method names.

Why use self if code works without it?

Using self. means that you are using the getter/setter, and not using it means that you are accessing the instance variable directly.

This question has been treated a lot here, but summarising:

ALWAYS create a @property for every data member and use “self.name” to
access it throughout your class implementation. NEVER access your own
instance variables directly.

Properties enforce access restrictions (such as readonly)

Properties enforce memory management policy (strong, weak)

Properties provide the opportunity to transparently implement custom
setters and getters.

Properties with custom setters or getters can be used to enforce a
thread-safety strategy. Having a single way to access instance
variables increases code readability.

Source:

Best Practices fr Obj-C

Difference between using self.variable and _variable when init these variables

The difference is simple: Using self.label = [[UILabel alloc] init] will actually invoke the method [self setLabel:[[UILabel alloc] init]], and using _label = [[UILabel alloc] init] will directly assign the value to the instance variable.

In practice what this means is that using the dot syntax is usually the best as the method invoked probably handles a lot of stuff for you, including:

  • Memory management: For example, if you declare a property with attribute 'strong' or 'retain', then the method invoked should retain the object assigned.
  • Key-Value Coding notifications: Maybe the class is key-value coding compliant for the property, which means the invoked method will notify the changes to observer objects.

Why would you not use the dot syntax? There are two potential reasons:

  • To avoid side effects: A good practice is to not use the dot syntax inside an initializer method. This is because we want to assign the value but don't want the other side effects of the invoked method for safety reasons.
  • Performance: This is probably rare, but maybe you are trying to implement a method with high performance and using instance variables directly can save the cost of invoking a method.

If you want to know more, I recommend reading this iOS guide which describes in more detail the ideas I mention here.

Should I use properties or direct reference when accessing instance variables internally?

I don't think any way is 'better'. You see both styles in common use, so there isn't even a usual/best practice now. In my experience, the style used has very little impact on how well I digest some implementation file I am looking. You certainly want to be comfortable with both styles (and any in between) when looking at other people's code.

Using a property for every internal ivar might be going slightly overboard, in terms of maintenance. I've done it, and it added a non-trivial amount of work that I don't think paid off for me. But if you have a strong desire/OCD for seeing consistent code like self.var everywhere, and you have it in the back of your mind every time you look at a class, then use it. Don't discount the effect that a nagging feeling can have on productivity.

Exceptions- Obviously, for custom getters (e.g. lazy creation), you don't have much of a choice. Also, I do create and use a property for internal setters when it makes it more convenient (e.g. setting objects with ownership semantics).

"just in case", "might" is not be a compelling reason to do something without more data, since the time required to implement it is non-zero. A better question might be, what is the probability that all the private ivars in some class will require KVC notifications in the future, but not now? For most of my own classes, the answer is exceedingly low, so I now avoid a hard rule about creating properties for every private ivar.

I've found that when dealing with internal implementations, I quickly get a good handle on how each ivar should be accessed regardless.

If you are interested, my own approach is this:

  • Reading ivars: Direct access, unless there is a custom getter (e.g. lazy creation)
  • Writing ivars: Directly in alloc/dealloc. Elsewhere, through a private property if one exists.

Access an instance variable from child classes

You can use "super" to call parent class initialize block and define instance variable "@var".
In that case you can modify value of this instance variable for another instance. Like this:

class Shape
def initialize ()
@var = "woohoo"
end
end

class Rectangle < Shape
def initialize(l, w)
@length = l
@width = w
super()
end

def area()
print @var
return @length * @width
end

def var=(new_value)
@var = new_value
end
end

a = Rectangle.new(1,1)
a.area
# => woohoo1
a.var = "kaboom"
a.area
# => kaboom1

b = Rectangle.new(2,2)
b.area
# => woohoo4

Or ofc you can use attr_accessor

class Shape
def initialize
@var = "woohoo"
end
end

class Rectangle < Shape

attr_accessor :var
def initialize(l, w)
@length, @width = l, w
super()
end

def area()
print @var
return @length * @width
end
end

a = Rectangle.new(1,1)
a.area
# => woohoo1
a.var = "kaboom"
a.area
# => kaboom1

b = Rectangle.new(2,2)
b.area
# => woohoo4

Instance variables in methods outside the constructor (Python) -- why and how?

Why is it best practice to initialize the instance variable within the
constructor?

Clarity.

Because it makes it easy to see at a glance all of the attributes of the class. If you initialize the variables in multiple methods, it becomes difficult to understand the complete data structure without reading every line of code.

Initializing within the __init__ also makes documentation easier. With your example, you can't write "an instance of Cat has a roar attribute". Instead, you have to add a paragraph explaining that an instance of Cat might have a "roar" attribute, but only after calling the "meow_louder" method.

Clarity is king. One of the smartest programmers I ever met once told me "show me your data structures, and I can tell you how your code works without seeing any of your code". While that's a tiny bit hyperbolic, there's definitely a ring of truth to it. One of the biggest hurdles to learning a code base is understanding the data that it manipulates.

What general/specific mess could arise if instance variables are
regularly initialized in methods other than the constructor?

The most obvious one is that an object may not have an attribute available during all parts of the program, leading to having to add a lot of extra code to handle the case where the attribute is undefined.

In what scenarios would it be better to initialize instance variables
in the other methods, rather than in the constructor?

I don't think there are any.

Note: you don't necessarily have to initialize an attribute with it's final value. In your case it's acceptable to initialize roar to None. The mere fact that it has been initialized to something shows that it's a piece of data that the class maintains. It's fine if the value changes later.



Related Topics



Leave a reply



Submit