Forum: Ruby Extrage behaviour when concatenating a string pointed from a constant and a string (with no space af

8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-07-20 02:04
(Received via mailing list)
Large subject.

Could you tell me why the NoMethodError is happening? I'm using Ruby
2.1.2
in Ubuntu 14.04.

Thanks in advance!

2.1.2 :020 > A = 'A'
 => "A"
2.1.2 :021 > B = 'B'
 => "B"
2.1.2 :022 > 'A' + 'B'
 => "AB"
2.1.2 :023 > 'A' +'B'
 => "AB"
2.1.2 :024 > A + B
 => "AB"
2.1.2 :025 > A +B
NoMethodError: undefined method `+@' for "B":String
    from (irb):25
    from /home/juanjo/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
2.1.2 :026 > A +'B'
NoMethodError: undefined method `+@' for "B":String
    from (irb):26
    from /home/juanjo/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
2.1.2 :027 > 'A' +B
 => "AB"
2.1.2 :028 > a = 'a'
 => "a"
2.1.2 :029 > a +'B'
 => "aB"

Greets!
5a837592409354297424994e8d62f722?d=identicon&s=25 Ryan Davis (Guest)
on 2014-07-20 03:46
(Received via mailing list)
On Jul 19, 2014, at 17:02, Juanjo Conti <jjconti@gmail.com> wrote:

> 2.1.2 :025 > A +B
> NoMethodError: undefined method `+@' for "B":String
>     from (irb):25
>     from /home/juanjo/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'

>> RubyParser.new.parse "A + B"
=> s(:call, s(:const, :A), :+, s(:const, :B))

>> RubyParser.new.parse "A +B"
=> s(:call, nil, :A, s(:call, s(:const, :B), :+@))

So it is seeing "A(+B)" where "+" is a unary method, much like "-".

Same as if you typed `N +4`, it'd see `N(+4)`, call unary + on 4, then
pass that as an arg to N.
8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-07-20 03:51
(Received via mailing list)
Right, thanks. But why that is not happening with a +"B"?


2014-07-19 22:45 GMT-03:00 Ryan Davis <ryand-ruby@zenspider.com>:
5a837592409354297424994e8d62f722?d=identicon&s=25 Ryan Davis (Guest)
on 2014-07-20 04:11
(Received via mailing list)
On Jul 19, 2014, at 18:50, Juanjo Conti <jjconti@gmail.com> wrote:

> Right, thanks. But why that is not happening with a +"B"?

Because you've already taught the interpreter that 'a' is a local
variable, so it knows it isn't `a(+"B")`, but `a + "B"`:

>> pp RubyParser.new.parse "a = 'a'; a +B"
s(:block,
 s(:lasgn, :a, s(:str, "a")),
 s(:call, s(:lvar, :a), :+, s(:const, :B)))
8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-07-21 04:10
(Received via mailing list)
I got it!

A can't be a method, because it's upcase!


2014-07-19 23:10 GMT-03:00 Ryan Davis <ryand-ruby@zenspider.com>:
09a32175057418748822c587ac08c429?d=identicon&s=25 Abinoam Jr. (abinoampraxedes_m)
on 2014-07-21 04:46
(Received via mailing list)
Dear Juanjo Conti,

def UPCASEMETHODISNOTAPROBLEM(arg)
  puts arg
end

UPCASEMETHODISNOTAPROBLEM "although not recommended"

Abinoam Jr.
3df767279ce7d81db0a5bb30f5136863?d=identicon&s=25 Matthew Kerwin (mattyk)
on 2014-07-21 04:57
(Received via mailing list)
On 21 July 2014 12:09, Juanjo Conti <jjconti@gmail.com> wrote:

> ​​
> I got it!
>
> A can't be a method, because it's upcase!
>
>
​Note quite​, upcase methods are allowed; see:
http://www.ruby-doc.org/core-2.1.2/Kernel.html#met...  Try
running:  Integer -4.2

​Consider this code:

    a + 1
    # we've never seen 'a =' before, so we assume it's a function​
    # first call a(), then on the resulting object call .+(1)
    # same as: a().+(1)

    a +1
    # <word> <space> <plus> <any> = function call
    # same as: a(1.+@())

    C + 1
    # C starts with a capital, so we assume it's a const
    # same as: C.+(1)

    C +1
    # <word> <space> <plus> <any> = function call
    # same as: C(1.+@())

    b = 2
    b + 1
    # we *have* seen 'b =' before, so we know it's an lvar
    # same as: b.+(1)

    b +1
    # <lvar> <space> <plus> <any> = *not* function call
    # same as "b + 1": b.+(1)


​You could do a similar​ thing with @x, @@y, or $z. Those are
unambiguously
variable names, so they'd never be interpreted as a function.


Have a think about what's going on here, if it helps:

irb(main):001:0> def a(*args) p [:a, *args]; end
irb(main):002:0> def b(*args) p [:b, *args]; end
irb(main):003:0> def C(*args) p [:C, *args]; end
irb(main):004:0> b = 1
irb(main):005:0> C = 99
irb(main):006:0> a +1
[:a, 1]
=> [:a, 1]  # a(1.+@())
irb(main):007:0> b +1
=> 2  # b.+(1)
irb(main):008:0> C +1
[:C, 1]
=> [:C, 1]  # C(1.+@)
irb(main):009:0> a + 1
[:a]
TypeError: no implicit conversion of Fixnum into Array
 from (irb):9:in `+'
 from (irb):9
from /usr/local/bin/irb-trunk:11:in `<main>'
# a().+(1)
irb(main):010:0> b + 1
=> 2  # b.+(1)
irb(main):011:0> C + 1
=> 100  # C.+(1)

​
8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-07-21 05:12
(Received via mailing list)
You're right.


2014-07-20 23:46 GMT-03:00 Abinoam Jr. <abinoam@gmail.com>:
8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-07-21 05:13
(Received via mailing list)
This email is really clear. Thanks!


2014-07-20 23:56 GMT-03:00 Matthew Kerwin <matthew@kerwin.net.au>:
8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-07-21 05:20
(Received via mailing list)
Ok... can I say that a method in upercase with no arguements can't be
called?

2.1.2 :010 > def Aja(*args)
2.1.2 :011?>   puts 'aja'
2.1.2 :012?>   end
 => :Aja
2.1.2 :013 > Aja
NameError: uninitialized constant Aja
    from (irb):13
    from /home/juanjo/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
2.1.2 :014 > Aja 1
aja
 => nil



2014-07-20 23:46 GMT-03:00 Abinoam Jr. <abinoam@gmail.com>:
3df767279ce7d81db0a5bb30f5136863?d=identicon&s=25 Matthew Kerwin (mattyk)
on 2014-07-21 06:58
(Received via mailing list)
On 21 July 2014 13:20, Juanjo Conti <jjconti@gmail.com> wrote:

>
>     from /home/juanjo/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
> 2.1.2 :014 > Aja 1
> aja
>  => nil
>
>
​You can add parentheses:

irb(main):001:0> def Aja *args
irb(main):002:1>   puts 'aja'
irb(main):003:1> end
=> :Aja
irb(main):004:0> Aja()
aja
=> nil

But generally speaking, yes, you need the arguments list to tell the
parser
that it's a function call.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.