A little summary about scope of variables and attr_ (my 2 cents)

The way I understand scope as of now, from narrow to large.
var is a local variable, within method,
@var is a instance variable, within class, changed locally
@@var is a class variable, within class, changed globally
attr_accessor, attr_reader :, within module (inter classes)
$var is a global variable, within entire program (do not use).

Would have been nice that attr_ be @@@, :slight_smile:

You just made my point.
Most reading I made about vars, do not mention attr_ , I mean as a scope level.

@var is an instance variable, and can belong to an individual instance of your class, or your class as a whole if referred to in a class method or directly in the class. Remember that classes are too objects in Ruby!

class Window
  # Let's say you have 5 windows. @count belongs to the class.
  @count = 5

  def self.some_class_method
    # Still belongs to class.
    @count
  end

  def some_instance_method
    # @width belongs to an individual instance of the Window class.
    @width = 1.m
  end
end

@@class_variables are rarely needed, and the style guide recommends against them due to their arguably not intuitive inheritance.

1 Like

Isn’t attr_reader, attr_writer and attr_accessor just automatically creating readers and writers for your instance attribute?

From my inderstanding, they do not create instance variables.

1 Like

Yes, you are very right. Thanks
Was exploring the scope point of view.

As said by @kengey, these are not variables. In your summary you mentioned the concept of scope (where in a program usage of a variable is valid).

But then there is also the concept of visibility (where in the program a variable can be seen and accessed). This only makes sense when the variable is still valid, namely persistent instance/class (and global) variables, whereas a local variable vanishes after the function end is executed. In Ruby, visibility is not a big matter because Ruby is special in that it makes variables private by default (invisible form outside). You cannot access an instance variable @var from outside the instance (instance.@var or instance.var). But if you want to access it, you can write a public method that returns the private variable and thus keeps control over access to it (def var; return @var; end).

attr_accessor is no more than a shortcut function that creates a new accessor function.

1 Like

Yes visibility.
I see a similarity in prefixing a var with @ or with attr_accessor.
The prefix sets the range of visibility: method, class or module.

attr_accessor and its siblings are not prefixes. They are just convenience methods (macros if you wish) to save you from typing the def code for instance methods to access instance variables from outside. They quite literally create the same code and pass it to the interpreter.

1 Like

That’s a local variable. Scoped to the current execution block. This can be the file (if it’s at the root level of the file) Or it can be at class/module level. Or within a ruby block.

This is an instance variable. Scoped to the instance of a class.

This is a class variable, scoped to the class itself.

These provide getter and setters for instance variables.

Correct.

Not sure what you mean by that? Can you elaborate? What are you trying to achieve?

1 Like

Right, that’s what I meant. I corrected my post.
Just a reflexion as I was listing scope of visibility of vars:
I had, in growing order : local, instance, class, ? , global. Nothing of the sort for module level.
But yes, there are attr_

Still not sure what you mean by this?
@@ is both for class and module variables. Both a class and module are very alike, with the difference you cannot create an instance of a module…

I never use global vars nor class/module vars. Only instance and block scoped ones.

I mean, I have 2 classes (in 2 rb. files), same Module.
The second is super to the first.
But there is one var the second needs to read from the first. I do not want to add yet another argument to all the methods just for this specific one.
attr_writer in the first and attr_reader in the second did it.
That is why I say, here it acts at “module level” for me.

I think you are experiencing the side effect of an overcomplication.

All methods you define on the super class are also available on the deriving class… and… any instance variable you declare on the super’s file, are available in the derivative.

Let me also give 2 cents: do not use inheritance, and certainly do not make a super class depend on a variable that an inherited one should set or declare.

Would you like to share the code with me? I’d love to have a look at it.

Think of it the other way around: There is one value/object the second needs to request (not grab) from the first.

Your situation is likely that you have to separate instances (?) that are very strongly coupled. Reading variable values from somewhere else is very prone to causing problems in future, because you rely on that the first class’s implementation does not change. What if the variable is removed?

Lean back for a moment and think about why class 2 needs access at all to information that is owned by class 1. What data do they need to exchange to function correctly? Write a method for accessing this data (attr_reader can do that for you). Then class 2 calls that method and “asks” to get the needed data. (There are more sophisticated ways of sharing data or composing classes so that they only loosely depend on each other.)

1 Like

Ah yes, as I said. Not fully tested yet, but seems to work with attr_reader

Ah, I think you may have read my post too fast. I know about super and sub class. It is the other way around.
But, yes my code is getting complex.

do not use inheritance,

First time I hear this, hum…

This is more and more often said about class inheritance (inheriting implementations from super classes), in contrast to type inheritance.

If the sole purpose of inheritance is code re-use, your super and subclasses can develop very strong dependencies on each other, which is bad. You loose flexibility because you are constraint by the super class’s implementation. It’s hard to read because for understanding the reader needs to jump between both. Behavior can become unpredictable if you use super within methods and move it one line up or down.
I would at least avoid having more than one level of inheritance (one direct super class).

1 Like

HUm… I see. I do feel my code is getting complicated. I have 2 levels of inheritance. In order to have only one, I could merge 2 files that will make kind of a long one. I thought small files were better.

Small files are good. It helps if you also split everything up in small classes. A class should do one thing and do that good. It’s a SOLID principle.

Par exemple, veuillez regarder ci: Les principes SOLID - Publicis Sapient Engineering - Engineering Done Right