Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do private setters behave differently to other private methods?

Tags:

ruby

Here's an interesting case I can't seem to explain. It looks like private setters are 'kind of' private, but sometimes there are exceptions to that. Regular private methods seem to behave differently to private setters:

class TestClass
  def do
    self.foo = :bar # fine
    self.baz        # error
  end

  private

  def foo=(other)
    @foo = other
  end

  def baz
  end
end

TestClass.new.do

The above code sets @foo just fine, despite being called on an explicit self. Then it fails to call #baz, because #baz is a private method.

What's up with this?

like image 251
Sam Morgan Avatar asked Mar 21 '17 15:03

Sam Morgan


People also ask

Should setter methods be private?

Usually you want setters/getters to be public, because that's what they are for: giving access to data, you don't want to give others direct access to because you don't want them to mess with your implementation dependent details - that's what encapsulation is about.

What will happen if setters and getters are made private?

The reason for declaring the getters and setters private is to make the corresponding part of the object's abstract state (i.e. the values) private. That's largely independent of the decision to use getters and setters or not to hide the implementation types, prevent direct access, etc.

What is the use of private set?

Private setters force you to set values inside of constructor or later.

Why variables should be defined as private and their getters and setters as public?

No outside class can access private data member (variable) of other class. However if we setup public getter and setter methods to update (for example void setSSN(int ssn) )and read (for example int getSSN() ) the private data fields then the outside class can access those private data fields via public methods.


2 Answers

Private setters are special because otherwise they couldn't be called at all:

foo = :bar

Assigns to the local variable foo, it doesn't send the message foo=.

Note that setters aren't the only things which cannot be called without an explicit receiver. +@, -@, !, ~, [], []=, +, -, *, /, %, &, |, ^, **, <<, >>, ==, ===, =~, !~, !=, <, >, <=, >=, <=> and probably some others I forgot also cannot be called without an explicit receiver. And then there's stuff like +=, <<= and so on.

There need to be exceptions for all of those. Unfortunately, there are only exceptions for some of those.

It has been proposed to change the rules for private from

Can only be called without an explicit receiver, except for [this long list of exceptions which is really complicated, and still not complete].

to

Can only be called without an explicit receiver or the literal special variable self as receiver.

which preserves all the current properties of the definition (the most important one being that it can be determined statically at parse time).

But so far, nothing has come of it.

like image 191
Jörg W Mittag Avatar answered Nov 13 '22 04:11

Jörg W Mittag


If you don't use self when using the setter method, it will instead assign the value to a local variable. More details.

In the code below, I've removed self from the assignment to foo, and you can see the the setter is not being used b/c @foo is nil:

  def do
    foo = :bar # fine
    baz        # error
    puts @foo  # prints nil
    puts foo   # prints 'bar'
  end
like image 28
Sunil D. Avatar answered Nov 13 '22 04:11

Sunil D.