Crystal: Calling private method with explicit receiver `self`

Created on 23 Apr 2018  路  8Comments  路  Source: crystal-lang/crystal

Calling a private method with explicit receiver self fails with the error message private method 'bar' called for Foo. In general, it is correct to avoid calling a private method with explicit receiver, but in the case of self it would make sense to allow for an exception.
Having the possibility to use self as explicit receiver is particularly useful when the return value of the private method is supposed to be stored in a synonymous local var: bar = self.bar. A valid alternative is bar = bar() but using self is often preferred and I think it would make sense to allow calling a private method with self.

Full example:

class Foo
  def foo
    bar = self.bar
  end

  private def bar
  end
end

Foo.new.foo
feature compiler

Most helpful comment

Why should the accessability of a method depend on how it was called - instead of just where it was called?

All 8 comments

The way you want it is not how it works in Ruby. You get the same error in Ruby.

Ruby does an exception with setters, because there's no way to invoke a private setter otherwise. Crystal does the same exception.

I don't see anything bad about writing bar(). Otherwise, mark the method as protected.

Why should the accessability of a method depend on how it was called - instead of just where it was called?

That's how Ruby works, and Crystal copies that.

It simplifies the logic a bit: if a method has an explicit receiver (any kind of reciever, even self), then a private method call will fail. Maybe that's the reason, so it's a fast check for a dynamic language.

Of course I wouldn't mind changing the semantic here, though we'll have to discuss the possible alternatives, taking into account modules, hierarchy, etc.

But then, I think I also wouldn't mind letting self be allowed in private methods. It's also a fast check and I honestly wanted it for a long time. Maybe we can move forward with that.

We shouldn't blindly copy ruby - it's not perfect. I think this is a good case for where ruby can be improved. I'd really like to see this scoping change in before 1.0.

We already have protected methods so surely the scope checking mechanisms are in place to make this check fairly easy.

Implementing this is super easy. However, what about this case:

class Foo
  private getter x

  def initialize(@x : Int32)
  end

  def ==(other : Foo)
    x == other.x
  end
end

Should it work or give an error? Right now it errors (there's a receiver), even though other is of the same class as where we are invoking the x method. For that you have to use protected, of course.

@asterite java allows that, and they're pretty serious about OO, so it's fine I guess?

perhaps only allow self reciever for private methods...

In case anyone stumbles upon this issue... This has also been changed in Ruby 2.7: self.foo() is now valid for a private method foo.

References:

I guess we can do the same then.

Was this page helpful?
0 / 5 - 0 ratings