Project

General

Profile

Feature #13581

Syntax sugar for method reference

Added by americodls (Americo Duarte) 9 months ago. Updated 4 days ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:81282]

Description

Some another programming languages (even Java, in version 8) has a cool way to refer a method as a reference.

I wrote some examples here: https://gist.github.com/americodls/20981b2864d166eee8d231904303f24b

I miss this thing in ruby.

I would thinking if is possible some like this:

roots = [1, 4, 9].map &Math.method(:sqrt)

Could be like this:

roots = [1, 4, 9].map Math->method

What do you guys thinking about it?


Related issues

Is duplicate of Ruby trunk - Feature #12125: Proposal: Shorthand operator for Object#methodOpen

History

#1 [ruby-core:81283] Updated by Hanmac (Hans Mackowiak) 9 months ago

that might collide with -> {} a lambda syntax
so i think the chances are low that ruby gets something like that.

so ruby probably does think its "Math(->sqrt)" and thats a Syntax error.

#2 [ruby-core:81285] Updated by americodls (Americo Duarte) 9 months ago

The -> was just a suggestion... Could be another symbol or combination of symbols like Math->>sqrt, Math=>>sqrt, Math+>sqrt, Math$>sqrt, Math:>sqrt, etc
I just think could have another way to write it than not a method calling with a symbol as argument, something more concise and expressive.

Hanmac (Hans Mackowiak) wrote:

that might collide with -> {} a lambda syntax
so i think the chances are low that ruby gets something like that.

so ruby probably does think its "Math(->sqrt)" and thats a Syntax error.

#3 [ruby-core:81286] Updated by Hanmac (Hans Mackowiak) 9 months ago

my current thinking is if that short form should do symbol support.

if Math->sym should be supported, than the normal variant need to be Math->:sqrt

i currently think if we also could abuse the call method.

so we could harness "Math.(:sqrt)" into something.

#4 [ruby-core:81296] Updated by americodls (Americo Duarte) 9 months ago

Why the version with symbol (Math->:sqrt) needs to be supported?

#5 [ruby-core:82556] Updated by matz (Yukihiro Matsumoto) 6 months ago

I am for adding syntax sugar for method reference. But I don't like proposed syntax (e.g. ->).
Any other idea?

Matz.

#7 [ruby-core:82580] Updated by Hanmac (Hans Mackowiak) 6 months ago

nobu (Nobuyoshi Nakada) wrote:

obj\.method

i am not sure about that:

obj\
.method

is already valid ruby code, so i am not sure

PS: when using "&obj.method(:symbol)" should that be optimized if able?

#8 [ruby-core:82582] Updated by zverok (Victor Shepelev) 6 months ago

I am for adding syntax sugar for method reference. But I don't like proposed syntax (e.g. ->).
Any other idea?

In my pet projects, I often alias method as m. It is readable enough, short enough and easy to remember, once you've seen it:

roots = [1, 4, 9].map(&Math.m(:sqrt))
%w[foo bar baz].each(&m(:puts))

..., and, if introduced into language core, can be easily backported to earlier versions (through something like backports or polyfill gem).

Another weird-ish idea, following the first one closely, is .:, which (for me) looks guessable:

[1,2,3].map(&Math.:sqrt)
%w[foo bar baz].each(&.:puts)

(BTW, object-less form should also be considered, when weighing proposals, don't you think?)

#9 [ruby-core:82583] Updated by k0kubun (Takashi Kokubun) 6 months ago

Another idea: &obj:method

It just puts receiver between & and : from existing one. I'm not sure it conflicts with existing syntax or not but I feel it's consistent with &:foo syntax.

roots = [1, 4, 9].map(&Math:sqrt)
%w[foo bar baz].each(&self:puts)

#10 [ruby-core:82584] Updated by Hanmac (Hans Mackowiak) 6 months ago

k0kubun (Takashi Kokubun) wrote:

Another idea: &obj:method

hm i like that idea, but think that might be a bit conflicting, that depends on if obj is an object or not?

obj = Object.new
obj:method #=> syntax error

but notice that: (xyz not known)

xyz:method #=> undefined method 'xyz' for main

it thinks that it's xyz(:method)

#11 [ruby-core:82586] Updated by k0kubun (Takashi Kokubun) 6 months ago

Oh, I'm so sad to hear obj:method (without &) is already valid. I still have hope to have it only when it's put with & in the last of arguments because that case is not valid for now.

irb(main):001:0> def obj(method); method; end
=> :obj
irb(main):002:0> obj:method
=> :method
irb(main):003:0> obj(&obj:method)
SyntaxError: (irb):3: syntax error, unexpected tSYMBEG, expecting keyword_do or '{' or '('
obj(&obj:method)
         ^
        from /home/k0kubun/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):004:0> obj(&(obj:method))
SyntaxError: (irb):4: syntax error, unexpected tLABEL
obj(&(obj:method))
          ^
        from /home/k0kubun/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):005:0> obj &obj:method
SyntaxError: (irb):5: syntax error, unexpected tSYMBEG, expecting keyword_do or '{' or '('
obj &obj:method
         ^
        from /home/k0kubun/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):006:0> obj &(obj:method)
SyntaxError: (irb):6: syntax error, unexpected tLABEL
obj &(obj:method)
          ^
        from /home/k0kubun/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'

I've never seen a person who writes a(:b) as a:b (without space or parenthesis before ":") and personally I don't expect &a:b to be &a(:b).

#12 [ruby-core:82588] Updated by nobu (Nobuyoshi Nakada) 6 months ago

Hanmac (Hans Mackowiak) wrote:

i am not sure about that:

obj\
.method

is already valid ruby code, so i am not sure

It's different at all.
My example is a token \., do not split.

PS: when using "&obj.method(:symbol)" should that be optimized if able?

Probably, but it's not possible to guarantee that it will return the method object.

#13 [ruby-core:82589] Updated by nobu (Nobuyoshi Nakada) 6 months ago

k0kubun (Takashi Kokubun) wrote:

Another idea: &obj:method

Consider more complex example, &(obj.some.method(args)):method, not only a simple reciever.
& and : are separated too far.

#14 [ruby-core:82590] Updated by Hanmac (Hans Mackowiak) 6 months ago

my idea for optimising &obj.method(:symbol)
is that it already creates a proc (object) without going over a Method object,
i don't know if that would be an good idea for that.

#15 [ruby-core:82597] Updated by mrkn (Kenta Murata) 6 months ago

How about obj.{method_name} for the syntax sugar of obj.method(:method_name)?

#16 [ruby-core:82611] Updated by zverok (Victor Shepelev) 6 months ago

Another pretty unholy idea: resemble the way Ruby docs document the methods:

[1,2,3].map(&Math#sqrt)
%w[foo bar baz].each(&#puts)

Yes, it conflicts with comment syntax, but in fact, no sane person should join the comment sign immediately after non-space symbol.

And we already have parsing ambiguities like this:

  • foo -bar → foo(-bar);
  • foo - bar → foo.-(bar).

#17 [ruby-core:82612] Updated by tom_dalling (Tom Dalling) 6 months ago

What about triple colon :::?

[1,2,3].map(&Math:::sqrt)
[1,2,3].each(&:::puts)

:: is for looking up constants, so it kind of makes sense that ::: is for looking up methods.

#18 [ruby-core:82614] Updated by tom-lord (Tom Lord) 6 months ago

Consider the following:

def get_method(sym, object = Object)
  object.send(:method, sym)
end

This allows us to write code like:

[1, 4, 9].map &get_method(:sqrt, Math)

So as an idea, how about introducing some syntax sugar for the above - such as:

[1, 4, 9].map &~>(:sqrt, Math)

Where in general, ~> (or whatever) could be the "method lookup operator".

For example, this would yield:

~>(:puts)       # => #<Method: Class(Kernel)#puts>
~>(:sqrt, Math) # => #<Method: Math.sqrt>
~>(:sqrt)       # => NameError: undefined method `sqrt' for class `#<Class:Object>'

#19 Updated by k0kubun (Takashi Kokubun) 5 months ago

  • Is duplicate of Feature #12125: Proposal: Shorthand operator for Object#method added

#20 [ruby-core:83365] Updated by americodls (Americo Duarte) 4 months ago

matz (Yukihiro Matsumoto) wrote:

I am for adding syntax sugar for method reference. But I don't like proposed syntax (e.g. ->).
Any other idea?

Matz.

What do you think about: Kernel:puts, Kernel~>puts, Kernel:>puts ?

#21 [ruby-core:85038] Updated by zverok (Victor Shepelev) 25 days ago

Just to push this forward, here are all the syntaxes from this and duplicate #12125.
I am taking Math.sqrt and puts as examples:

  • map(&Math->sqrt) (and just each(&->puts) probably?) -- Matz is explicitly against it;
  • map(&Math\.sqrt) (not sure about puts);
  • map(&Math.m(:sqrt)), each(&m(:puts)) (just shortening, no language syntax change)
  • map(&Math.:sqrt), each(&.:puts)
  • map(&Math:sqrt), each(&self:puts)
  • map(&Math#sqrt), each(&#puts) (it was my proposal, "just how it looks in docs", but I should reconsider: in docs it is Math::sqrt, in fact)
  • map(&Math:::sqrt), each(&:::puts)
  • map(&~>(:sqrt, Math)), each(&~>(:puts))
  • several by @Papierkorb:
    • map(&Math.>sqrt), each(&.>puts) (nobu (Nobuyoshi Nakada): conflicts with existing syntax)
    • map(&Math<sqrt>), each(&<puts>) (nobu (Nobuyoshi Nakada): conflicts with existing syntax)
    • map(&Math&>sqrt), each(&&>puts)
    • map(&Math|>sqrt), each(&|>puts) (too confusable with Elixir-like pipe, probably)

Can please please somebody lift this question to next Developer Meeting and make an Executive Decision?..

I personally really like .: (called "tetris operator" in other ticket).

#22 [ruby-core:85053] Updated by dsferreira (Daniel Ferreira) 25 days ago

zverok (Victor Shepelev) wrote:

map(&Math|>sqrt), each(&|>puts) (too confusable with Elixir-like pipe, probably)

I tend to agree with that.
In fact I was hoping to get the pipe operator introduced in ruby. (Created an issue with that in mind: https://bugs.ruby-lang.org/issues/14392).

Taking that pipe operator example as an operator that sends messages maybe we can use it to send a message to the class or module. Like this:

:sqrt |> Math

Since Math is not a method the message would extract the method from the object.

If this is not practical maybe we could invert the operator and do:

Math <| :sqrt

#23 [ruby-core:85114] Updated by nobu (Nobuyoshi Nakada) 24 days ago

zverok (Victor Shepelev) wrote:

  • map(&Math.>sqrt), each(&.>puts)

This conflicts with existing syntax.

Not this.

#24 [ruby-core:85115] Updated by zverok (Victor Shepelev) 24 days ago

nobu (Nobuyoshi Nakada) Thanks, I've updated the list.

Can you please add it to next Developer Meeting's agenda?..

#25 [ruby-core:85329] Updated by mpapis (Michal Papis) 16 days ago

Not sure it's worth it - but while we are at this thinking of a shorthand one of the proposals &Math&>sqrt made me think if it could be automated and all the iterators could recognize methods and we could avoid the initial & to this map(Math...) - skipped the operator as it's not clear what's preferred.

My two cents to the operator - what about ! and @ would they conflict? (yes for the Kernel, not sure about Class'es).

#26 [ruby-core:85330] Updated by nobu (Nobuyoshi Nakada) 16 days ago

mpapis (Michal Papis) wrote:

Not sure it's worth it - but while we are at this thinking of a shorthand one of the proposals &Math&>sqrt made me think if it could be automated and all the iterators could recognize methods and we could avoid the initial & to this map(Math...) - skipped the operator as it's not clear what's preferred.

It can't distinguish passing block and passing Method object.

My two cents to the operator - what about ! and @ would they conflict? (yes for the Kernel, not sure about Class'es).

Math!sqrt and Math@sqrt?
They are valid syntax now.

You can try with ruby -c.

$ ruby -wc -e 'Math!sqrt'
Syntax OK

$ ruby -wc -e 'Math@sqrt'
Syntax OK

They are interpreted as a method call without a receiver, Math(!sqrt) and Math(@sqrt) respectively.

#27 [ruby-core:85332] Updated by duerst (Martin Dürst) 16 days ago

nobu (Nobuyoshi Nakada) wrote:

$ ruby -wc -e 'Math!sqrt'
Syntax OK

$ ruby -wc -e 'Math@sqrt'
Syntax OK

They are interpreted as a method call without a receiver, Math(!sqrt) and Math(@sqrt) respectively.

This may be just me, but I think this kind of syntax without spaces could (or even should) be depreciated.

That doesn't mean that for the purpose of this issue, I like ! or @. But they might be usable for other purposes.

#28 [ruby-core:85334] Updated by nobu (Nobuyoshi Nakada) 16 days ago

duerst (Martin Dürst) wrote:

This may be just me, but I think this kind of syntax without spaces could (or even should) be depreciated.

It would hurt code-golfers and quine-makers. :)

#29 [ruby-core:85340] Updated by Hanmac (Hans Mackowiak) 16 days ago

Question for nobu (Nobuyoshi Nakada) :

i don't know about the rubyVM but can xyz(&method(:symbol)) or xyz(&obj.method(:symbol)) be optimized like xyz(&:symbol) is?
the one with the Symbol was optimized to not create a Proc object if not needed.

can be something similar with the Method object? or if not overwritten maybe not even creating a Method object at all?

#30 [ruby-core:85341] Updated by nobu (Nobuyoshi Nakada) 16 days ago

Hanmac (Hans Mackowiak) wrote:

i don't know about the rubyVM but can xyz(&method(:symbol)) or xyz(&obj.method(:symbol)) be optimized like xyz(&:symbol) is?

They have different meanings all.

xyz(&method(:symbol)) == xyz {|x| symbol(x)}
xyz(&obj.method(:symbol)) == xyz {|x| obj.symbol(x)}
xyz(&:symbol) == xyz {|x| x.symbol}

#31 [ruby-core:85342] Updated by Hanmac (Hans Mackowiak) 16 days ago

nobu (Nobuyoshi Nakada) wrote:

Hanmac (Hans Mackowiak) wrote:

i don't know about the rubyVM but can xyz(&method(:symbol)) or xyz(&obj.method(:symbol)) be optimized like xyz(&:symbol) is?

They have different meanings all.

xyz(&method(:symbol)) == xyz {|x| symbol(x)}
xyz(&obj.method(:symbol)) == xyz {|x| obj.symbol(x)}
xyz(&:symbol) == xyz {|x| x.symbol}

i know they are different meanings,
i was just wondering if they can be optimized for the VM too, to make them run faster if able
like with not creating extra ruby objects if not needed

#32 [ruby-core:85345] Updated by nobu (Nobuyoshi Nakada) 16 days ago

Hanmac (Hans Mackowiak) wrote:

i know they are different meanings,

Sorry, misread.

i was just wondering if they can be optimized for the VM too, to make them run faster if able
like with not creating extra ruby objects if not needed

Once a Method as the result of & to passing a block is allowed, optimization of calling a Method object might be possible by adding a new block handler type for methods.
No "extra ruby objects" would be the next step.

#33 [ruby-core:85380] Updated by landongrindheim (Landon Grindheim) 14 days ago

  • map(&Math->sqrt) (and just each(&->puts) probably?) -- Matz is explicitly against it;

Is map(&Math.&(:sqrt) viable? Perhaps it would be confused with the safe navigation operator.

#34 [ruby-core:85381] Updated by jeremyevans0 (Jeremy Evans) 13 days ago

landongrindheim (Landon Grindheim) wrote:

Is map(&Math.&(:sqrt) viable? Perhaps it would be confused with the safe navigation operator.

No. It would break backward compatibility, as that is currently interpreted as:

Math.&(:sqrt).to_proc

That code currently works if you do:

def Math.&(x) proc{|a| a} end

#35 [ruby-core:85409] Updated by sevos (Artur Roszczyk) 13 days ago

Have we ruled out map(&obj:method) syntax? Intuitively I find it consistent with Symbol#to_proc

class Foo
  def initialize(array)
    @array = array
  end

  def call
    @array
      .map(&Math:sqrt)
      .map(&self:magic)
      .map(&self:boo(2.0))
      .map(&:ceil)
      .each(&Kernel:puts)
  end

  private

  def magic(x)
    x ** 3
  end

  def boo(a, b)
    a / b
  end
end

Alternatively, I am for triple colon:

class Foo
  def initialize(array)
    @array = array
  end

  def call
    @array
      .map(&Math:::sqrt)
      .map(&self:::magic)
      .map(&:::boo(2.0)) # with triple colon we could omit self
      .map(&:ceil)
      .each(&Kernel:::puts)
  end

  private

  def magic(x)
    x ** 3
  end

  def boo(a, b)
    a / b
  end
end

This could translate to:

class Foo
  def initialize(array)
    @array = array
  end

  def call
    @array
      .map  { |x| Math.public_send(:sqrt, x) }
      .map  { |x| self.send(:magic, x) }
      .map  { |x| self.send(:boo, x, 2.0) }
      .map  { |x| x.ceil }
      .each { |x| Kernel.public_send(:puts, x) }
  end

  private

  def magic(x)
    x ** 3
  end

  def boo(a, b)
    a / b
  end
end

Applying additional arguments (aka .map(&self:boo(2.0)) is just a proposal - I am not sure if this should be even possible - Symbol#to_proc does not allow that.

Another interesting question which we need to answer is:

What visibility scope should be used when making a method call?

Given the syntax receiver:method or receiver:::method if the receiver is self then we should expand this syntax sugar to send() allowing accessing the private interface of the current object (which is not the item from the iterator - we would use symbol to proc in that case). However, if the receiver is something else, we should expand to public_send to disallow accessing private methods of other objects.

Just my two cents ;)

Cheers,
Artur

#36 [ruby-core:85439] Updated by nobu (Nobuyoshi Nakada) 12 days ago

Note that &: isn't a single operator, but combination of & prefix + a part of :symbol.
So it should be valid syntax solely without &.

#37 [ruby-core:85440] Updated by sevos (Artur Roszczyk) 12 days ago

After a while I am becoming a bigger fan of the triple colon operator. We could implement a class MethodSelector for handling the logic and the operator would be expected to return an instance of the class:

class MethodSelector
  def initialize(b, receiver, m)
    @binding = b
    @receiver = receiver
    @method = m
  end

  def call(*args, **kwargs, &block)
    # ...
  end

  def to_proc
    if @binding.eval("self") == @receiver
      proc do |*args, **kwargs, &block|
        if kwargs.empty?
          @receiver.send(@method, *args, &block)
        else
          @receiver.send(@method, *args, **kwargs, &block)
        end
      end
    else
      proc do |*args, **kwargs, &block|
        if kwargs.empty?
          @receiver.public_send(@method, *args, &block)
        else
          @receiver.public_send(@method, *args, **kwargs, &block)
        end
      end
    end
  end
end

# Instead of MS() method we should implement ::: operator (taking two argiments):
# receiver:::method expands to MS(binding, receiver, method)
class Object
  def MS(b, receiver, m)
    MethodSelector.new(b, receiver, m)
  end
end

# Example usage
> MS(binding, Kernel, :puts) # the triple colon operator should expand current binding by default
=> #<MethodSelector:0x007fdba89bd0a8 @binding=#<Binding:0x007fdba89bd0d0>, @receiver=Kernel, @method=:puts>
> [1,2,3].each(&MS(binding, Kernel, :puts))
1
2
3
=> nil

There is still the question how to enable meta-programming with triple colon operator.
Imagine the situation when the method name is dynamic. How to distinguish it from the symbol?

method = :puts

Kernel:::puts
Kernel:::method

The only logical solution to me is the presence of the fourth colon for the symbol:

method = :puts

Kernel::::puts # evaluates as Kernel:::(:puts)
Kernel:::method # evaluates as Kernel:::(method)

What are your thoughts?

#38 [ruby-core:85441] Updated by phluid61 (Matthew Kerwin) 12 days ago

sevos (Artur Roszczyk) wrote:

What are your thoughts?

I have two:

  1. As always: do we really need more magic symbols? I like reading Ruby because it's not Perl.

  2. If you're adding new syntax, you don't have to be clever. Symbol has :"#{x}" so why not propose y:::"#{x}"? Not that it adds much over y.method(x)

#39 [ruby-core:85443] Updated by sevos (Artur Roszczyk) 12 days ago

phluid61 (Matthew Kerwin) wrote:

sevos (Artur Roszczyk) wrote:

What are your thoughts?

I have two:

  1. As always: do we really need more magic symbols? I like reading Ruby because it's not Perl.
    I totally agree, but we still like -> {} syntax for lambdas, right? Let's play with ideas, maybe we can find something nice for a method selector, too ;)

  2. If you're adding new syntax, you don't have to be clever. Symbol has :"#{x}" so why not propose y:::"#{x}"? Not that it adds much over y.method(x)

You're totally right! I was looking at triple-colon as an operator taking two arguments. Your idea of looking at this as a double-colon lookup operator is actually great, look:

irb(main):006:0> a :: :to_s
SyntaxError: (irb):6: syntax error, unexpected tSYMBEG, expecting '('
a :: :to_s
      ^
    from /Users/sevos/.rbenv/versions/2.4.0/bin/irb:11:in `<main>'
irb(main):007:0> Kernel :: :t
SyntaxError: (irb):7: syntax error, unexpected tSYMBEG, expecting tCONSTANT
A :: :t
      ^
    from /Users/sevos/.rbenv/versions/2.4.0/bin/irb:11:in `<main>'

We already have a lookup operator which takes object, constant on the left side and method name or constand on the right side.
Maybe it would be possible to support symbols on the right side and expand them to method(:symbol) call?
I would like just to emphasise again the need of respecting the method-to-be-called visibility depending on the current binding.

#40 [ruby-core:85445] Updated by phluid61 (Matthew Kerwin) 12 days ago

sevos (Artur Roszczyk) wrote:

phluid61 (Matthew Kerwin) wrote:

sevos (Artur Roszczyk) wrote:

What are your thoughts?

I have two:

  1. As always: do we really need more magic symbols? I like reading Ruby because it's not Perl.

I totally agree, but we still like -> {} syntax for lambdas, right? Let's play with ideas, maybe we can find something nice for a method selector, too ;)

Personally I hate it, and never use it. I like my code to say lambda when I make a Lambda, and (more often) proc when I make a Proc.

  1. If you're adding new syntax, you don't have to be clever. Symbol has :"#{x}" so why not propose y:::"#{x}"? Not that it adds much over y.method(x)

You're totally right! I was looking at triple-colon as an operator taking two arguments. Your idea of looking at this as a double-colon lookup operator is actually great, [...]

Actually I was just suggesting a simple token, like obj:::foo or obj.:foo; if you really want to accept variable method names why not obj:::"#{x}" or obj.:"#{x}"?

Although I doubt I'd ever use it.

(Personally I find the idea of partially applied methods more useful.)

Cheers

#41 [ruby-core:85513] Updated by cben (Beni Cherniavsky-Paskin) 5 days ago

A non-syntax idea: could Math.method.sqrt look significantly nicer than Math.method(:sqrt)?
That is, .method without args would return a magic object that for any message returns the bound method of that name.

[1, 4, 9].map(&Math.method.sqrt).each(&method.puts)
[1, 4, 9].map(&Math.method(:sqrt)).each(&method(:puts))
[1, 4, 9].map{|*a| Math.sqrt(*a)}.each{|*a| puts(*a)}

Naive implementation (some names don't work, eg. Math.method.method_missing, and doesn't take visibility and refinements into account):

class Methods < BasicObject
  def initialize(obj)
    @obj = obj
  end
  def method_missing(name)
    @obj.method(name)
  end
  def responds_to_missing?(name)
    true
  end
end

module MethodWithoutArgs
  def method(*args)
    if args.empty?
      Methods.new(self)
    else
      super
    end
  end
end
Object.prepend(MethodWithoutArgs)

[14] pry(main)> [1, 4, 9].map(&Math.method.sqrt).each(&method.puts)
1.0
2.0
3.0
=> [1.0, 2.0, 3.0]

BTW, what about refinements? Is .method(:foo) ignorant about them? A benefit of a real syntax might be that it could "see" methods from lexically active refinements.

As for syntax, I'm wondering if something postfix might work. The reason I say this is I'm thinking of both &: and this as shorthands for writing out a block.
&: can be read locally, it roughly "stands for" |x| x. :

[1, 2, 3].map{|x| x.to_s}
[1, 2, 3].map(&:to_s)

And with a bound method, we want to elide the argument declaration, plus the call that comes after the receiver.message:

[1, 4, 9].map{|*a| Math.sqrt(*a)}.each{|*a| puts(*a)}
[1, 4, 9].map(&Math.sqrt:).each(&puts:)  # half baked idea
[1, 4, 9].map(Math.sqrt&).each(puts&)    # quarter baked

OK, actually there is a more generic feature I'd love much more than a syntax for bound methods: implicit notation for block arg:

[1, 2, 3].map{|x| x.to_s}
[1, 2, 3].map{_.to_s}

[1, 4, 9].map{|x| Math.sqrt(x)}.each{|x| puts(x)}
[1, 4, 9].map{Math.sqrt(_)}.each{puts(_)}

[1, 2, 3].map{|x| 1/x}
[1, 2, 3].map{1/_}

(I don't think _ is possible, just an example)

The part I love most about this is that {} does not become (&...)!
This doesn't easily handle multiple args, like bound methods do, but I think one arg is sweet spot for such shorthand anyway.

  • I've tried prototyping this once by defining Kernel._ that would look in caller frame, but didn't find any way to access arg in a block that didn't declare any |args|.

#42 [ruby-core:85533] Updated by sevos (Artur Roszczyk) 4 days ago

cben (Beni Cherniavsky-Paskin) wrote:

A non-syntax idea: could Math.method.sqrt look significantly nicer than Math.method(:sqrt)?
That is, .method without args would return a magic object that for any message returns the bound method of that name.

Hey Beni! Thank you! This is a great idea! For my taste it looks significantly better!

Also, I took the liberty of implementing a prototype gem and I've added my two cents:
- method visibility check
- arguments currying

You can check it out on Github

Also available in: Atom PDF