V Wed, 12 Dec 2018 17:40:15 +0100 Stefan Hundhammer <[email protected]> napsáno:
> [shundhammer @ morgul] ~/tmp % cat weird.rb > #!/usr/bin/ruby > > class Weird > attr_accessor :foo > > def initialize > @foo = "foo" > end > > def doit1 > puts "doit1" > puts foo + "bar" > end > > def doit2 > puts "doit2" > puts foo +"bar" > end > end > > weird = Weird.new > weird.doit1 > weird.doit2 > > > [shundhammer @ morgul] ~/tmp % ./weird.rb > doit1 > foobar > doit2 > Traceback (most recent call last): > 1: from ./weird.rb:23:in `<main>' > ./weird.rb:17:in `doit2': wrong number of arguments (given 1, expected 0) > (ArgumentError) > Well, at least ruby syntax check returns you warning (and of course rubocop also). Maybe we can simply check for warning in this check in travis? As we already did syntax check, but it is not hard failure because meta programming can potentially allows you to survive this situation. try it yourself: ruby -wc weird.rb # w is warning and c is syntax check /tmp/weird.rb:17: warning: ambiguous first argument; put parentheses or a space even after `+' operator Syntax OK Josef > > What's going on here? > Why does it crash? > What's the difference between "doit1" and "doit2"? > > > (Spoiler alert: solution after the blank lines) > > > > > > > > > > > > > > > > > > > > > Yes, it's just that one blank after the plus operator, and it makes all the > difference. > > It turns out that some time ago (with Ruby 2.3), the Ruby string class got a > brand new unary plus operator (which is what we had all been missing for so > long, of course). That unary plus calls String.unfreeze on that string. > > And in Ruby, the parentheses for a function call are optional. > > This is an accident waiting to happen, and it happened right here: > Ruby interpreted this as a function call because the plus can be interpreted > as an unary plus here, so it decided to unfreeze the constant "bar" string > and pass it as an argument to the foo() method - which exists; it is the > getter to the @foo member variable (implicitly created by attr_accessor: > foo). Of course, this getter does not accept any parameter, so it complains. > > Actually it's pure luck that it does not accept a parameter and complains > instead; if it had been a function that can accept a parameter, it would have > happily called it with the unfrozen "bar" string and just done random garbage > with that unintended parameter. > > > ARGH. > > This is when "meaning good" (as in "the opposite of doing good") meets duck > typing and happily executing any random garbage. > > If I really want to unfreeze a frozen string, I will happily tell Ruby to do > just that. But no, there was a chance to make a cryptic scripting language > even more cryptic by introducing stuff like an unary plus operator for > strings, of all things. > > Tricky programming is soooo cool. > Readable and maintainable code is sooo overrated. > > ARGH. > > > > Kind regards -- To unsubscribe, e-mail: [email protected] To contact the owner, e-mail: [email protected]
