[bikeshed] Syntactic sugar idea

D

Daniel DeLorme

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?
 
G

Gregory Brown

It seems that often an object will be passed into a block only to invoke
a method of that object:
=A0arr.map{ |obj| obj.some_method }

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

Does that make any sense?
RUBY_VERSION =3D> "1.9.1"
%w[foo bar baz].map(&:upcase)
=3D> ["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

--=20
BOOK: http://rubybestpractices.com
TECH: http://blog.majesticseacreature.com
NON-TECH: http://metametta.blogspot.com
 
D

Daniel DeLorme

Jan said:
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
 
G

Gregory Brown

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 yo= u
could even do map{.foo.bar} =A0:)

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
 
R

Rob Biedenharn

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


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 Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
D

Daniel DeLorme

Rob said:
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
 
J

Joel VanderWerf

Daniel said:
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...
 
G

Gregory Brown

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
 
J

Joshua Ballanco

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...

Isn't this essentially the "with" syntax from Javascript? I think that
could fit into a future version of Ruby...


- Josh
 
D

Daniel DeLorme

Gregory said:
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
 
R

Robert Klemme

2009/5/14 Daniel DeLorme said:
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
 
C

Clifford Heath

Robert said:
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 Heath.
 
L

Lars Christensen

It seems that often an object will be passed into a block only to invoke
a method of that object:
=A0arr.map{ |obj| obj.some_method }

So I had the (weird? stupid?) thought that it would be nice to have some
syntactic sugar like this:
=A0arr.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.
 
B

Bill Kelly

From: "Lars Christensen said:
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
 
M

Mark Thomas

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?
 
C

Charles Oliver Nutter

Daniel said:
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
 
C

Charles Oliver Nutter

Robert said:
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
 
R

Robert Klemme

2009/5/14 Charles Oliver Nutter said:
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
 
C

Charles Oliver Nutter

Robert said:
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);
}
 
R

Robert Dober

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

=A0 arr.sort_by { $_.size }
=A0 File.open("logfile", "a") { $_.puts logtext }
=A0 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





--=20
Si tu veux construire un bateau ...
Ne rassemble pas des hommes pour aller chercher du bois, pr=E9parer des
outils, r=E9partir les t=E2ches, all=E9ger le travail=85 mais enseigne aux
gens la nostalgie de l=92infini de la mer.

If you want to build a ship, don=92t herd people together to collect
wood and don=92t assign them tasks and work, but rather teach them to
long for the endless immensity of the sea.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top