Fwd: Is anyone using -w?

On Thu, Jun 26, 2014 at 10:58 AM, Robert K.
[email protected] wrote:

Why would you? bar= is defined.

That’s how ruby responds when you try to call a private method using
the explicit self receiver:

class Foo
def use_bar_explicit_self
self.bar
end

private
def bar
‘bar’
end
end

foo = Foo.new
foo.use_bar_explicit_self

~> -:3:in use_bar_explicit_self': private method bar’ called for

#Foo:0x007fe9c982cd68 (NoMethodError)

~> from -:13:in `’

This works in exactly the same way when you pass a variable to a method:

class Foo
def use_bar_explicit_self(var)
self.bar(var)
end

private
def bar(var)
‘bar’
end
end

foo = Foo.new
foo.use_bar_explicit_self(:a_var)

~> -:3:in use_bar_explicit_self': private method bar’ called for

#Foo:0x007fdfea828a30 (NoMethodError)

~> from -:13:in `’

But the same rules don’t seem to follow when using the = operator

class Foo
def value
@bar
end

def use_bar_explicit_self=(var)
self.bar=(var)
end

private
def bar=(var)
@bar = var
end
end

foo = Foo.new
foo.use_bar_explicit_self = :a_var
foo.value # => :a_var

I’m guessing that the = operator essentially results in doing a send
to "#{method_name}= and therefore is bypassing ruby’s usual method
visibility rules.

Btw. 1.9.3 also did not choke with this.

Yep - also 1.8.7 and rubinius 2.2.2 - so I guess this is expected
behaviour. It just surprised me :slight_smile:

On Thu, Jun 26, 2014 at 1:02 PM, Steve T. [email protected]
wrote:

On Thu, Jun 26, 2014 at 10:58 AM, Robert K.
[email protected] wrote:

Why would you? bar= is defined.

That’s how ruby responds when you try to call a private method using
the explicit self receiver:

Oh right. I thought it was another error. I just looked at the
message. I’m sorry.

But the same rules don’t seem to follow when using the = operator

Right. Apparently that is handled specially. That makes sense if you
consider that there is no other way to invoke assignment methods other
than prefixing with “self.”.

I’m guessing that the = operator essentially results in doing a send
to "#{method_name}= and therefore is bypassing ruby’s usual method
visibility rules.

I don’t think it necessarily needs to go through #send to allow this
to happen. There just needs to be a different call chain for things
like “self.{identifier}={expression}”. But we can test:

$ ruby xx.rb
42
SEND
43
$ cat xx.rb
class Foo
def send(*x) puts “SEND”; super end

private
attr_accessor :bar

public
def set_bar(b)
self.bar = b
end

def set_bar_2(b)
send(“bar=”, b)
end

def get_bar
bar
end
end

f = Foo.new
f.set_bar(42) # no warning except under -w
puts f.get_bar # outputs 42
f.set_bar_2(43)
puts f.get_bar # outputs 43

Voilá!

Btw. 1.9.3 also did not choke with this.

Yep - also 1.8.7 and rubinius 2.2.2 - so I guess this is expected
behaviour. It just surprised me :slight_smile:

I also was not aware. Learn something new every day. :slight_smile:

Kind regards

robert

On 06/23/2014 04:30 AM, Sylvain J. wrote:

I’ve been wanting to use -w … However, I found out that quite a few
high-profile gems out there are not clean under -w (e.g. pry), meaning
that I have a hard time using -w myself.

How many people actually do use -w ? Is this really a “best practice”
in the ruby world these days ?

Here’s one reason I avoid -w:

class PointOnTimeline
def initialize time
@t0 = time # might be Time or something else
end

def do_something_with_other_time time
time < @t0 # fail fast if time and @t0 are not comparable
return “something”
end
end

The code is generic with respect to the objects used as times. We don’t
want to assert that they are Time instances, only that they can be
compared.

However:

$ ruby -w t.rb
t.rb:7: warning: possibly useless use of < in void context

Yep, we called #< without using the result. So, what to do? Assign it to
an unused local? That’s a warning. Wrap it in if ... end? Ok, no
warning, but that looks strange. Is there a missing then clause?

Maybe the best -w clean version is:

time.send(:<, @t0)

But that doesn’t really make the intent clearer, and in fact it suggests
a different intent: that we’re trying to call a private method.

Yep - also 1.8.7 and rubinius 2.2.2 - so I guess this is expected
behaviour. It just surprised me :slight_smile:

Yes. It arises because of the need to differentiate between local
variable assignment and the call to a setter:

class Dog
def x=(val)
@x = val.capitalize
end

def do_stuff
x = 10 #local variable assignment
self.x = “hello” #call to setter
puts x
puts @x
end

end

Dog.new.do_stuff

–output:–
10
Hello

Now if you make the setter private, you can’t write:

def do_stuff

x = ‘hello’

end

and expect ruby to interpret that as:

self.x=(‘hello’)

because that assignment once again creates a local variable. Hence, the
exception to the ‘no explicit receivers for private methods’ rule.
David Black might have discussed this in “The Well Grounded Rubyist”.
David?

On Jun 26, 2014, at 17:28, Joel VanderWerf [email protected]
wrote:

class PointOnTimeline
The code is generic with respect to the objects used as times. We don’t want to
assert that they are Time instances, only that they can be compared.

However:

$ ruby -w t.rb
t.rb:7: warning: possibly useless use of < in void context

Yep, we called #< without using the result. So, what to do? Assign it to an
unused local? That’s a warning. Wrap it in if ... end? Ok, no warning, but that
looks strange. Is there a missing then clause?

You can assign to _:

_ = time <=> @t0

You can wrap it in a function call to make it more obvious what you’re
doing (I certainly can’t tell WHY you’re doing that):

assert(time <=> @t0)

(I think <=> makes more sense in both cases since that’s what you really
want)

You can write less clever code. I prefer this one, personally. Having it
fail on actual usage is a hell of a lot more clear / understandable /
debuggable than some quippy line at the top of the method (yes, even
with the comment). I shouldn’t have to think to decipher your intent.

raise ArgumentError, “…” unless time.comparable_with? @t0

  1. a good exception message saying what went wrong.
  2. code that describes what it is doing AND why.
  3. no warnings.

we all win.

Adam W. wrote in post #1150594:

Hi guys,

what is -w? It’s incredible hard to Google :slight_smile:

FYI, if you’re having trouble Googling special symbols you can try
http://www.symbolhound.com/

On 06/26/2014 05:39 PM, Ryan D. wrote:

On Jun 26, 2014, at 17:28, Joel VanderWerf [email protected] wrote:

class PointOnTimeline
def initialize time
@t0 = time # might be Time or something else
end

def do_something_with_other_time time
time < @t0 # fail fast if time and @t0 are not comparable
return “something”
end
end

assert(time <=> @t0)

That’s not bad at all. Spaceship returns truthy, unless incomparable,
and this will work for any Comparable.