[bikeshed] Syntactic sugar idea

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

···

2009/5/14 Daniel DeLorme <dan-ml@dan42.com>:

Gregory Brown wrote:

On Thu, May 14, 2009 at 12:16 AM, Daniel DeLorme <dan-ml@dan42.com> 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.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Daniel DeLorme wrote:

Gregory Brown 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

···

On Thu, May 14, 2009 at 12:16 AM, Daniel DeLorme <dan-ml@dan42.com> wrote:

Robert Klemme 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 Heath.

Robert Klemme 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

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

···

2009/5/14 Charles Oliver Nutter <charles.nutter@sun.com>

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme 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);
              }