Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does Ruby throw warnings for private attributes

Take the example class:

# in ./example.rb
class Example
  private
    attr_accessor :name
end

When I run it in verbose mode, Ruby throws warnings at me:

$ ruby -W2 ./example.rb
example.rb:3: warning: private attribute?

Why is this not recommended?

like image 596
shime Avatar asked Aug 19 '13 07:08

shime


2 Answers

Because it doesn't make much sense to define a getter/setter that is not visible from the outside in most cases. We generally use attr_accessor only to expose an instance variable outside of the class. However, the private keyword defeats this purpose by making the generated getter/setter methods invisible to the outside world.

The only reason you would want to use a private setter/getter is when there is some additional logic involved. In this case, however, you would have to define those methods manually with def, anyway.

like image 133
Patrick Oscity Avatar answered Oct 28 '22 18:10

Patrick Oscity


Although I've accepted @padde's answer, I would like to share some code for future reference.

I wanted to check @Babai's answer about the default access levels of the attribute methods.

So here's how it works. I'll demonstrate on the source from 2.0.0-p247.

This is the source of attr_accessor:

static VALUE
rb_mod_attr_accessor(int argc, VALUE *argv, VALUE klass)
{
    int i;

    for (i=0; i<argc; i++) {
rb_attr(klass, rb_to_id(argv[i]), TRUE, TRUE, TRUE);
    }
    return Qnil;
}

As you can see, it's calling the rb_attr function for each argument. (I'm guessing argc stands for argument counter.) So we have to look at the rb_attr source to understand how this all works:

void
rb_attr(VALUE klass, ID id, int read, int write, int ex)
{
    const char *name;
    ID attriv;
    VALUE aname;
    rb_method_flag_t noex;

    if (!ex) {
      noex = NOEX_PUBLIC;
    }
    else {


      if (SCOPE_TEST(NOEX_PRIVATE)) {
        noex = NOEX_PRIVATE;
        rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
          "attribute accessor as module_function" :
          "private attribute?");
      }
      else if (SCOPE_TEST(NOEX_PROTECTED)) {
        noex = NOEX_PROTECTED;
      }
      else {
        noex = NOEX_PUBLIC;
      }
    }

    /* more logic that's not relevant for this explanation */
}

As you can see, the interpreter checks if the access level is NOEX_PRIVATE and raises errors if it is.

like image 26
shime Avatar answered Oct 28 '22 17:10

shime