Forum: Ruby Syntactic sugar idea

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Daniel DeLorme (Guest)
on 2009-05-14 06:44
(Received via mailing list)
It seems that often an object will be passed into a block only to invoke
a method of that object:
   arr.map{ |obj| obj.some_method }

So I had the (weird? stupid?) thought that it would be nice to have some
syntactic sugar like this:
   arr.map{ .some_method }

Does that make any sense?
Gregory B. (Guest)
on 2009-05-14 06:53
(Received via mailing list)
On Wed, May 13, 2009 at 10:42 PM, Daniel DeLorme 
<removed_email_address@domain.invalid>
wrote:
> It seems that often an object will be passed into a block only to invoke
> a method of that object:
>  arr.map{ |obj| obj.some_method }
>
> So I had the (weird? stupid?) thought that it would be nice to have some
> syntactic sugar like this:
>  arr.map{ .some_method }
>
> Does that make any sense?

>> RUBY_VERSION
=> "1.9.1"
>> %w[foo bar baz].map(&:upcase)
=> ["FOO", "BAR", "BAZ"]

On Ruby 1.8.6, you can implement this easily as:

class Symbol
  def to_proc
    lambda { |x| x.send(self)
  end
end

-greg
Flower B. (Guest)
on 2009-05-14 06:55
(Received via mailing list)
* Daniel DeLorme <removed_email_address@domain.invalid> [2009-05-14 11:42:31 
+0900]:

> It seems that often an object will be passed into a block only to invoke
> a method of that object:
>   arr.map{ |obj| obj.some_method }
>
> So I had the (weird? stupid?) thought that it would be nice to have some
> syntactic sugar like this:
>   arr.map{ .some_method }

You can do arr.map(&:some_method) in ruby 1.9

-J
Daniel DeLorme (Guest)
on 2009-05-14 07:04
(Received via mailing list)
Jan wrote:
> You can do arr.map(&:some_method) in ruby 1.9
Yes, I know, and that was kind of my point. The to_proc conversion
became popular because people want a shortcut notation for this common
case, but IMHO map(&:foo) is way uglier than map{.foo}, and as a bonus
you could even do map{.foo.bar}  :-)

-Daniel
Gregory B. (Guest)
on 2009-05-14 07:07
(Received via mailing list)
On Wed, May 13, 2009 at 11:03 PM, Daniel DeLorme 
<removed_email_address@domain.invalid>
wrote:

> Yes, I know, and that was kind of my point. The to_proc conversion
> became popular because people want a shortcut notation for this common
> case, but IMHO map(&:foo) is way uglier than map{.foo}, and as a bonus you
> could even do map{.foo.bar}  :-)

I don't know.   I think they're about the same in terms of looks, and
the former doesn't require changes to the parser.

-greg
Rob B. (Guest)
on 2009-05-14 07:34
(Received via mailing list)
On May 13, 2009, at 11:07 PM, Gregory B. wrote:
> the former doesn't require changes to the parser.
>
> -greg


plus, doing your .foo.bar has to contend with .foo being nil (or
otherwise having a NoMethodError for :bar)

some_collection.map{|e|e.foo.bar}

really isn't too bad anyway and if you want to handle the possible
exception:

some_collection.map{|e|e.foo.bar rescue nil}

possibly with a .compact thrown on the end.

The parser already refused to treat .5 as a Float literal insisting
that it be 0.5 so I doubt that .foo would get any more favorable
treatment as a special case (since .5 isn't really all that special).

-Rob

Rob B.    http://agileconsultingllc.com
removed_email_address@domain.invalid
Daniel DeLorme (Guest)
on 2009-05-14 08:16
(Received via mailing list)
Rob B. wrote:
> The parser already refused to treat .5 as a Float literal insisting that
> it be 0.5 so I doubt that .foo would get any more favorable treatment as
> a special case (since .5 isn't really all that special).

Well, you never know... Matz *did* add the Symbol#to_proc conversion in
1.9 and also the foo\n.bar "fluent interface" syntax. So apparently
trivial changes *do* make their way into core... sometimes.

-Daniel
Joel VanderWerf (Guest)
on 2009-05-14 08:28
(Received via mailing list)
Daniel DeLorme wrote:
> It seems that often an object will be passed into a block only to invoke
> a method of that object:
>   arr.map{ |obj| obj.some_method }
>
> So I had the (weird? stupid?) thought that it would be nice to have some
> syntactic sugar like this:
>   arr.map{ .some_method }
>
> Does that make any sense?

It would be nice for avoiding instance_eval in DSLs:

@x = 400
@y = 300

config "my window" do
   .width @x
   .height @y
end

but I just don't see how to fit it into ruby...
Gregory B. (Guest)
on 2009-05-14 09:14
(Received via mailing list)
On Thu, May 14, 2009 at 12:16 AM, Daniel DeLorme 
<removed_email_address@domain.invalid>
wrote:
> Rob B. wrote:
>>
>> The parser already refused to treat .5 as a Float literal insisting that
>> it be 0.5 so I doubt that .foo would get any more favorable treatment as a
>> special case (since .5 isn't really all that special).
>
> Well, you never know... Matz *did* add the Symbol#to_proc conversion in
> 1.9 and also the foo\n.bar "fluent interface" syntax. So apparently
> trivial changes *do* make their way into core... sometimes.

But Symbol#to_proc is not a parser change. It's just using an existing
hook that has been around in Ruby 1.8

-greg
Joshua B. (Guest)
on 2009-05-14 09:20
(Received via mailing list)
On May 14, 2009, at 12:27 AM, Joel VanderWerf wrote:

>
> but I just don't see how to fit it into ruby...
Isn't this essentially the "with" syntax from Javascript? I think that
could fit into a future version of Ruby...


- Josh
Daniel DeLorme (Guest)
on 2009-05-14 10:09
(Received via mailing list)
Gregory B. wrote:
> On Thu, May 14, 2009 at 12:16 AM, Daniel DeLorme <removed_email_address@domain.invalid> 
wrote:
>> Well, you never know... Matz *did* add the Symbol#to_proc conversion in
>> 1.9 and also the foo\n.bar "fluent interface" syntax. So apparently
>> trivial changes *do* make their way into core... sometimes.
>
> But Symbol#to_proc is not a parser change. It's just using an existing
> hook that has been around in Ruby 1.8

But the fluent interface change *is* a parser change. My point was just
that seemingly trivial requests *can* make it into the core, whether
they're a syntax change or not.

-Daniel
Robert K. (Guest)
on 2009-05-14 11:16
(Received via mailing list)
2009/5/14 Daniel DeLorme <removed_email_address@domain.invalid>:
>
> But the fluent interface change *is* a parser change. My point was just that
> seemingly trivial requests *can* make it into the core, whether they're a
> syntax change or not.

We always need to balance cost and benefit.  In this case to me the
benefit seems to be outweighed by costs whereas the other change can
have an impact on readability.  YMMV though.

Cheers

robert
Clifford H. (Guest)
on 2009-05-14 12:16
(Received via mailing list)
Robert K. wrote:
> We always need to balance cost and benefit.  In this case to me the
> benefit seems to be outweighed by costs

Right, what folk might not realise is that the 1.8 version constructed
an object on each usage which had to be GC'd later, whereas in the 1.9
version it can be free. So there was good reason to support it directly.

Clifford H..
Lars C. (Guest)
on 2009-05-14 13:33
(Received via mailing list)
On Thu, May 14, 2009 at 4:42 AM, Daniel DeLorme 
<removed_email_address@domain.invalid>
wrote:
> It seems that often an object will be passed into a block only to invoke
> a method of that object:
>  arr.map{ |obj| obj.some_method }
>
> So I had the (weird? stupid?) thought that it would be nice to have some
> syntactic sugar like this:
>  arr.map{ .some_method }

I sometimes miss Perl's $_. Without a parser change, it could be used
as the default name for block parameters:

   arr.sort_by { $_.size }
   File.open("logfile", "a") { $_.puts logtext }
   arr.map { foo2bar($_) }

Then I remember how people abuse it and avoid using appropriately
named variables, and I am again happy about the little extra code I
have to write.
Bill K. (Guest)
on 2009-05-14 14:29
(Received via mailing list)
From: "Lars C." <removed_email_address@domain.invalid>
>
> I sometimes miss Perl's $_.

Not that I'm advocating its use, but... Ruby does support $_
for perl-like command line scripting:

$ ruby -ne 'puts "dollar_underscore is: #$_"' /usr/share/dict/words |
head
dollar_underscore is:
dollar_underscore is: A
dollar_underscore is: A's
dollar_underscore is: AOL
dollar_underscore is: AOL's
dollar_underscore is: Aachen
dollar_underscore is: Aachen's
dollar_underscore is: Aaliyah
dollar_underscore is: Aaliyah's
dollar_underscore is: Aaron


Regards,

Bill
Mark T. (Guest)
on 2009-05-14 16:05
(Received via mailing list)
This is a neat idea, but wouldn't it conflict with the "fluent
interface" construct? Using Joel's DSL example:

config "my window" do
   .width @x
   .height @y
end

if we changed it to

config "my window" do
   .width calculate_width
   .height @y
end

Now how does the parser know what .height refers to: calculate_width,
or the implicit block variable?
Charles Oliver N. (Guest)
on 2009-05-14 17:36
(Received via mailing list)
Daniel DeLorme wrote:
> It seems that often an object will be passed into a block only to invoke
> a method of that object:
>   arr.map{ |obj| obj.some_method }
>
> So I had the (weird? stupid?) thought that it would be nice to have some
> syntactic sugar like this:
>   arr.map{ .some_method }
>
> Does that make any sense?

Groovy has this in the form of the "it" magic variable:

[1,2,3].each {puts it}

While I absolutely hate the moniker "it" the idea itself has grown on
me. Perhaps something more scala-like:

[1,2,3].each {puts _}

Or a pseudo-global:

[1,2,3].each {puts $it}

I hacked "it" to work in JRuby once recently, and it's not difficult.

- Charlie
Charles Oliver N. (Guest)
on 2009-05-14 17:38
(Received via mailing list)
Robert K. wrote:
> We always need to balance cost and benefit.  In this case to me the
> benefit seems to be outweighed by costs whereas the other change can
> have an impact on readability.  YMMV though.

The cost isn't high. 15 minutes of work in JRuby, probably more in CRuby
but not by a lot.

- Charlie
Robert K. (Guest)
on 2009-05-14 17:45
(Received via mailing list)
2009/5/14 Charles Oliver N. <removed_email_address@domain.invalid>
>
> Robert K. wrote:
>>
>> We always need to balance cost and benefit.  In this case to me the
>> benefit seems to be outweighed by costs whereas the other change can
>> have an impact on readability.  YMMV though.
>
> The cost isn't high. 15 minutes of work in JRuby, probably more in CRuby but not by a 
lot.

That's likely only implementation.  Then there is testing,
documentation and before that checking that there are no negative
effects of the change.  If there are - and there seems to be evidence
that this is the case in Mark's posting - those negative effects also
count as costs...

Kind regards

robert
Charles Oliver N. (Guest)
on 2009-05-14 18:04
(Received via mailing list)
Robert K. wrote:
> That's likely only implementation.  Then there is testing,
> documentation and before that checking that there are no negative
> effects of the change.  If there are - and there seems to be evidence
> that this is the case in Mark's posting - those negative effects also
> count as costs...

Bah, I say.

~/projects/jruby âž” jruby -X-C -e '[1,2,3].each {puts $it}'
1
2
3

Diff follows.

diff --git a/src/org/jruby/RubyGlobal.java
b/src/org/jruby/RubyGlobal.java
index f25bd42..c107a7b 100644
--- a/src/org/jruby/RubyGlobal.java
+++ b/src/org/jruby/RubyGlobal.java
@@ -199,6 +199,7 @@ public class RubyGlobal {

          runtime.defineVariable(new ErrorInfoGlobalVariable(runtime,
"$!", runtime.getNil()));
          runtime.defineVariable(new NonEffectiveGlobalVariable(runtime,
"$=", runtime.getFalse()));
+        runtime.defineVariable(new ImplicitItGlobalVariable(runtime,
"$it"));

          if(runtime.getInstanceConfig().getInputFieldSeparator() ==
null) {
              runtime.defineVariable(new GlobalVariable(runtime, "$;",
runtime.getNil()));
@@ -320,6 +321,24 @@ public class RubyGlobal {
          }
      }

+    private static class ImplicitItGlobalVariable extends
GlobalVariable {
+        public ImplicitItGlobalVariable(Ruby runtime, String name) {
+            super(runtime, name, null);
+        }
+
+        @Override
+        public IRubyObject set(IRubyObject value) {
+            return
runtime.getCurrentContext().getCurrentScope().setImplicitArg(value);
+        }
+
+        @Override
+        public IRubyObject get() {
+            IRubyObject obj =
runtime.getCurrentContext().getCurrentScope().getImplicitArg();
+            if (obj == null) obj = runtime.getNil();
+            return obj;
+        }
+    }
+
      private static class LastExitStatusVariable extends GlobalVariable
{
          public LastExitStatusVariable(Ruby runtime, String name) {
              super(runtime, name, runtime.getNil());
diff --git a/src/org/jruby/runtime/DynamicScope.java
b/src/org/jruby/runtime/DynamicScope.java
index e2f6e90..9ad9deb 100644
--- a/src/org/jruby/runtime/DynamicScope.java
+++ b/src/org/jruby/runtime/DynamicScope.java
@@ -39,6 +39,8 @@ public abstract class DynamicScope {
      // been called.
      protected DynamicScope evalScope;

+    protected IRubyObject implicitArg;
+
      protected DynamicScope(StaticScope staticScope, DynamicScope
parent) {
          this.staticScope = staticScope;
          this.parent = parent;
@@ -165,6 +167,14 @@ public abstract class DynamicScope {
          return staticScope.getAllNamesInScope();
      }

+    public IRubyObject getImplicitArg() {
+        return implicitArg;
+    }
+
+    public IRubyObject setImplicitArg(IRubyObject implicitArg) {
+        return this.implicitArg = implicitArg;
+    }
+
      /**
       * Get backref
       */
diff --git a/src/org/jruby/runtime/InterpretedBlock.java
b/src/org/jruby/runtime/InterpretedBlock.java
index 8015be8..4291066 100644
--- a/src/org/jruby/runtime/InterpretedBlock.java
+++ b/src/org/jruby/runtime/InterpretedBlock.java
@@ -162,6 +162,7 @@ public class InterpretedBlock extends BlockBody {
          Frame lastFrame = pre(context, null, binding);

          try {
+            context.getCurrentScope().setImplicitArg(value);
              if (hasVarNode) {
                  setupBlockArg(context, varNode, value, self);
              }
Robert D. (Guest)
on 2009-05-14 18:47
(Received via mailing list)
On Thu, May 14, 2009 at 11:33 AM, Lars C.
<removed_email_address@domain.invalid> wrote:
> as the default name for block parameters:
>
>   arr.sort_by { $_.size }
>   File.open("logfile", "a") { $_.puts logtext }
>   arr.map { foo2bar($_) }
>
> Then I remember how people abuse it and avoid using appropriately
> named variables, and I am again happy about the little extra code I
> have to write.
>
>
Forget the $ and you are spelling out a thought I was bearing with me
for quite some time, ty Daniel and Joel to bring this up :).
I always wanted an implicit _ parameter in blocks, as e.g.
3.times do puts _ end





--
Si tu veux construire un bateau ...
Ne rassemble pas des hommes pour aller chercher du bois, préparer des
outils, répartir les tâches, alléger le travail… mais enseigne aux
gens la nostalgie de l’infini de la mer.

If you want to build a ship, don’t herd people together to collect
wood and don’t assign them tasks and work, but rather teach them to
long for the endless immensity of the sea.
Joel VanderWerf (Guest)
on 2009-05-14 20:42
(Received via mailing list)
Mark T. wrote:
> config "my window" do
>    .width calculate_width
>    .height @y
> end
>
> Now how does the parser know what .height refers to: calculate_width,
> or the implicit block variable?

Yeah, seems impossible. Maybe if there were some other character instead
of "." to signify sending a message to the block's "default object".
Jörg W Mittag (Guest)
on 2009-05-15 02:30
(Received via mailing list)
Daniel DeLorme wrote:
> Gregory B. wrote:
>> On Thu, May 14, 2009 at 12:16 AM, Daniel DeLorme <removed_email_address@domain.invalid> 
wrote:
>>> Well, you never know... Matz *did* add the Symbol#to_proc conversion in
>>> 1.9 and also the foo\n.bar "fluent interface" syntax. So apparently
>>> trivial changes *do* make their way into core... sometimes.
>> But Symbol#to_proc is not a parser change. It's just using an existing
>> hook that has been around in Ruby 1.8
> But the fluent interface change *is* a parser change. My point was just
> that seemingly trivial requests *can* make it into the core, whether
> they're a syntax change or not.

Was that fluent interface syntax really a request? I cannot remember
anyone asking for it. I do, however, vividly recall various petitions
to *remove* that change.

jwm
Daniel B. (Guest)
on 2009-05-15 02:31
(Received via mailing list)
On May 13, 8:42 pm, Daniel DeLorme <removed_email_address@domain.invalid> wrote:
> It seems that often an object will be passed into a block only to invoke
> a method of that object:
>    arr.map{ |obj| obj.some_method }
>
> So I had the (weird? stupid?) thought that it would be nice to have some
> syntactic sugar like this:
>    arr.map{ .some_method }

require 'enumerable/extra'

arr.map(:some_method)

Regards,

Dan
Jeremy McAnally (Guest)
on 2009-05-15 04:06
(Received via mailing list)
Mmm losing the $ would then render RSpec completely inoperable since
it has an it method.

--Jeremy

On Thu, May 14, 2009 at 9:46 AM, Robert D. 
<removed_email_address@domain.invalid>
wrote:
>>
>>
> --
> Antoine de Saint-Exupéry
>
>



--
http://jeremymcanally.com/
http://entp.com/
http://omgbloglol.com

My books:
http://manning.com/mcanally/
http://humblelittlerubybook.com/ (FREE!)
Mark T. (Guest)
on 2009-05-15 04:45
(Received via mailing list)
On May 14, 6:31 pm, Daniel B. <removed_email_address@domain.invalid> wrote:
> require 'enumerable/extra'
>
> arr.map(:some_method)
>
> Regards,
>
> Dan

Cool! What would it take to make this 1.9 compatible?
This topic is locked and can not be replied to.