Introducing the "it" keyword

Greg Fodor wrote:

$_ releases after the method.

Ah. This works today:

return $_ if $_ = opts[:user]

But it's still hard to read :slight_smile:

At least in one case I know what's the variable here. For $_ that is,
opts might be anything.

And don't forget:

$_ = "foo"
puts $_ if ($_ = "bob" && chomp)

will print "foo"!

Which has nothing to do with $_ or chomp using $_ behind the scenes.
It's a problem with operator precedence.

It works as if you've written

  $_ = "foo"
  puts $_ if ($_ = ("bob" && chomp))

Which means you could get the same confusion if you tried

x = 'foo'
puts x if (x = 'bob' && 1 > 0)

Though there's a chance that the "true" you get in this case would
suggest better what's the problem.

(I feel like I'm back writing Perl again)

I wish I was.

And actually talking about Perl and $_, the way you'd "remember a
subexpression to use it several times" would be

for (<the expression goes here>) {
  return $_ if $_ > 45 and f($_) and whatever( 'with', $_)
}

the difference from

$_ = <the expression goes here>);
return $_ if $_ > 45 and f($_) and whatever( 'with', $_)

being that the for(){} localizes the change of $_. That is, $_ only gets
the new value within the "loop". Which is something the proposed "it"
would have to provide as well.

Jenda

···

--
Posted via http://www.ruby-forum.com/\.

Greg Fodor wrote:

but here are a few other ideas:

puts it if (x + y) * (it = (a - b)) < 10

This one already works. No changes to ruby needed.

···

--
Ist so, weil ist so
Bleibt so, weil war so

<snip>

>>
> That is something I am surprised about, b/c the intention was to have
> an idiom for
> return it if h(x) < 10

No, it's "return it if it < 10" with "it" being "v+1" in this case.

Well that was the original idiom but we are looking for existing ones, right?

> and
> return it_test(h(x))
> really is not the same, right?

It's not the same but I believe you misread the task. it_test is just a
method to demonstrate the idiom in lines 2-4.

Ah that's why you called the method test_..., not stupid at all :wink:
Well I will get to understand what is going on here...
... eventually...
... potentially...
... maybe...
... hardly...

Cheers
Robert

Kind regards

        robert

Cheers
Robert

···

On 5/27/07, Robert Klemme <shortcutter@googlemail.com> wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

I take this back, unless someone can come up with a solution ot the
following problem:

def a(x)
  return it if x.abs.it! != 1
  0
end

z = Complex[1, 1]
p it if a(z.conj.it!) # prints 1.414..., not Complex[1, -1]

Aur Saraf

···

On 5/30/07, SonOfLilit <sonoflilit@gmail.com> wrote:

Hi all,

That is a very interesting and educating discussion :slight_smile:

Lately, I came up with #dump!. What is #dump, you ask? It is a
solution to my problem with #p :

Let's say that I have the line of code:
  v = matrix*Vector[1, 1, function(a)] + vector.invert
Now, let's say that I think I have a bug in there.

Normally, if I'm not into using a debugger (perhaps because that's in
an inner loop and I want to filter the one buggy run from among 1000),
I am forced to do this:
  f_a = function(a)
  v_i = vector.invert
  m_v = matrix * Vector[1, 1, f_a]
  v = m_v + v_i
  p "debug:", f_a, v_i, m_v, v
and of course, after I'm done, re-structure the code because it's an
ugly way of doing things in a language that doesn't use polish
notation.

Here's my solution:

module Kernel
  def dump!(message = nil)
    print " ::: #{caller[1]} ::: "
    print "#message} ::: " if message
    puts self.inspect # well, actually I use #to_yaml
    return self
  end

and lo!:
  v = matrix*Vector[1, 1, function(a).dump!("debugging that v
bug")].dump! + vector.invert.dump!
  v.dump! # I could put it in the prev line with parens, but that's ugly
no restructuring needed. This can go anywhere. And in the less messy
cases, I don't even need to remove those dump! calls, I can just
redefine dump! to return self silently.

That, IMHO, is "the Ruby Way".

In the same code that made me implement that, I've had many cases that
call for "it", and used the simpler techniques in this thread to
overcome it (placing "(a == stuff) and rest_of_expression" within an
if, using a temp var, etc').

Here's what I'm gonna do now:

module Kernel
  def it!
    $sonoflilit_it = self
  end
  def it
    $sonoflilit_it
  end
end

return it if (heavy_calc(param, param2, param3.moreheavylifting(param4)).it!

or

it.print if matrix.inverse.it!.is_what_i_want
nil.it!

There still is the problem of garbage collection. nil.it! solves it
manually in those critical cases, like it being a large matrix.

An alternative version would be:

module Kernel
  def it!(key = :it_secret_default_key)
    $sonoflilit_its[key] = self
  end
  def it(key = :it_secret_default_key)
    $sonoflilit_its[key]
  end
  def pop_it(key = :it_secret_default_key)
    $sonoflilit_its.delete(key) # notice that it returns it. might be useful
  end
  def clean_its
    $sonoflilit_its.clean
  end
end

for cases like:

if a.calculation.it!(:a).abs > b.calculation2.it!(:b).real_part
  puts it(:a).det
else
  puts func(it(:b))
end
clean_its

While previous examples work without change (though the idiom of
nil.it! isn't recommended for the nil.it(:sym) case, since the hash
will still keep a member there and with time it could become memory
consuming).

This is not a general solution, and might look bad to some, but it
serves me well. Feel free to paste it into your own project.

Aur Saraf

On 5/30/07, Charles Oliver Nutter <charles.nutter@sun.com> wrote:
> dblack@wobblini.net wrote:
> > The argument from precedent is tricky, though. I'd say the presence
> > of $_ and $~ and friends suggests, not that more local globals are
> > desireable, but that Ruby has reached, and perhaps exceeded, its quota
> > of them :slight_smile:
>
> No argument from me :slight_smile:
>
> I still think "it" is a terrible keyword to introduce though.
>
> - Charlie
>

I'm afraid I must disagree. The only thing I find "unreadable" about
that is the complete lack of obvious association between %$ and the
source of the value it contains/labels. The composition of the
expression itself, such that the condition test is on the same line as
the rest of the action, produces absolutely zero difficulty for me.

I get the impression that you don't like the predicate conditional form
at all, then, and would rather it was stricken from the language. Yes?

···

On Thu, May 31, 2007 at 11:30:30AM +0900, Michael W. Ryder wrote:

While I realize the Ruby is not C, I think that some of the style
guidelines for C should still apply in Ruby. One of the ones that was
very important was to make each statement do only one thing. Your
example of setting a temporary variable to an amount on one line and
then testing that variable on the second line is much easier to read,
and understand, quickly than your statements like 'return %$ unless f(n)
== x'. This becomes even more important when the test is even more
convoluted such as checking for the position of a string in another
string and returning if it is in a specific location.

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
Ben Franklin: "As we enjoy great Advantages from the Inventions of others
we should be glad of an Opportunity to serve others by any Invention of
ours, and this we should do freely and generously."

Unfortunately this would greatly complicate the situation in which a return without value is intended...

Ellie

Eleanor McHugh
Games With Brains

···

On 31 May 2007, at 06:35, Robert Dober wrote:

But maybe things should really by simple

return if x > 42
return unless (x+1)%2 == 0 # not zero? here

could probably made syntactically work (differently than now) and
return the LHS of the expression iff the expression evaluates to true
or false respectively.

----
raise ArgumentError unless @reality.responds_to? :reason

> $_ = "foo"
> puts $_ if ($_ = "bob" && chomp)

> will print "foo"!

Which has nothing to do with $_ or chomp using $_ behind the scenes.
It's a problem with operator precedence.

I disagree. Using 'it' here would avoid worries about side-effects.

Anyway, I thought ruby was moving away from these implicit magic $*
variables? Using pipes, the assignment to it would be explicit and
safe from side effects.

for (<the expression goes here>) {
  return $_ if $_ > 45 and f($_) and whatever( 'with', $_)
}

the difference from

$_ = <the expression goes here>);
return $_ if $_ > 45 and f($_) and whatever( 'with', $_)

being that the for(){} localizes the change of $_.

Right, this is kinda sorta the pattern I am trying to kill
with "it", except it is less verbose. In addition, you still
have side effects on $_ as above, you'd generally have to
grab $_ into a local (with a name) if you were going to use
methods that *could* change it.

This one already works. No changes to ruby needed.

NameError: undefined local variable or method `x' for main:Object

One thing to mention. Coming up with examples that come close
to the semantics of 'it' (without exact semantics) is missing
the point. If these other solutions were optimal people would
be using them already, but as far as I've seen lots of ruby
code has the pattern implemented lazily.

There are really two genuine criticisms to 'it' I can see
based upon this thread:

- The syntax is too confusing
- It is not worth polluting the language over, despite its utility

Upon reflection, unless I am mistaken, there *is* something close
with correct semantics, a la the references to 'let' and
'for' in Scheme and Perl. It seems kind of odd nobody has given
this one before, since it is pretty simple and I feel dumb for
not mentioning it until now.

def with(x)
  yield x
end

with (v + 1) { |it| return it if it < 5 }

Personally, I think this is the closest we can get in Ruby, and
can serve as a concrete starting point for what we gain by
introducing a keyword. Based upon this 'it' now officially
gains sugar and performance, since this above example can match
the same semantics and side effects.

Why it is good sugar:
- Less code. The value for 'it' moves much closer to its usage.

- Less explicit naming. If 'it' becomes the default name for the
block parameter and also is set during end of line conditionals,
ruby code will be less polluted with throwaway user variable names.
(This is a pet peeve of mine, why do I have to keep saying x,y,z
and my co-worker says a,b,c? If we just use 'it', its consistent.)

- It will result in ruby idioms that are clean and correct. If the
above example works go great, why aren't people using it? Probably
because it's a lot of extra typing for perceived little gain, even
though it is the most 'correct' implementation. I feel like this
common pattern should be supported in the most terse form possible.

Why it is good for performance:
- We save a full block invocation and binding opposed to the above,
I think. I don't know enough about the interpreter to be sure of
this, though.

Also, even if 'it' was just added as the default first name, you
could get:

def with (x); yield x; end;

with (v + 1) { puts it if it < 5 }

This might be a good compromise!

<snip>

>>
> That is something I am surprised about, b/c the intention was to have
> an idiom for
> return it if h(x) < 10

No, it's "return it if it < 10" with "it" being "v+1" in this case.

Well that was the original idiom but we are looking for existing ones, right?

Yes, and that's why I presented what I presented. I am not sure I understand your point here. :slight_smile:

> and
> return it_test(h(x))
> really is not the same, right?

It's not the same but I believe you misread the task. it_test is just a
method to demonstrate the idiom in lines 2-4.

Ah that's why you called the method test_..., not stupid at all :wink:
Well I will get to understand what is going on here...
.. eventually...
.. potentially...
.. maybe...
.. hardly...

Um... It's really not that difficult. I just used instance_eval because that will rebind "self" inside the block but retain the original binding afterwards. That way you get something like a "temporary variable" but without needing to manually make sure the reference is released after the test. Remeber that the problem with my first suggestion was that you had to add tmp=nil after the line with return in order to make sure the object would be released again.

It is really just the built in way of doing what is known in other languages as "with":

irb(main):001:0> def with(x,&b) x.instance_eval(&b) end
=> nil
irb(main):002:0> with "" do
irb(main):003:1* p length
irb(main):004:1> p empty?
irb(main):005:1> end
0
true
=> nil
irb(main):009:0> with "aaaaaaaaa" do
irb(main):010:1* scan(/a{1,3}/) {|x| p x}
irb(main):011:1> end
"aaa"
=> "aaaaaaaaa"
irb(main):012:0>

Hope that explains it. If not, let me know.

Kind regards

  robert

···

On 27.05.2007 11:46, Robert Dober wrote:

On 5/27/07, Robert Klemme <shortcutter@googlemail.com> wrote:

z = Complex[1, 1]
p it if a(z.conj.it!) # prints 1.414..., not Complex[1, -1]

If there's anything our functional programming friends can
teach us, it's that side effects will always come back to
bite you. :slight_smile:

I like your syntax, though. Perhaps there is some wizardry
that could be done that would get the semantics of let()
but the syntax of it!() ?

Chad Perrin wrote:

While I realize the Ruby is not C, I think that some of the style guidelines for C should still apply in Ruby. One of the ones that was very important was to make each statement do only one thing. Your example of setting a temporary variable to an amount on one line and then testing that variable on the second line is much easier to read, and understand, quickly than your statements like 'return %$ unless f(n) == x'. This becomes even more important when the test is even more convoluted such as checking for the position of a string in another string and returning if it is in a specific location.

I'm afraid I must disagree. The only thing I find "unreadable" about
that is the complete lack of obvious association between %$ and the
source of the value it contains/labels. The composition of the
expression itself, such that the condition test is on the same line as
the rest of the action, produces absolutely zero difficulty for me.

The problem is when trying to maintain the code. Suppose you have to change the test and it changes what is referenced by %$x or $1 or whatever is used. Now you have to try and determine what you need to use for the return to get the correct value. I find that harder than having one line determine the test value and a separate line determining what is done with that value.
As I am still maintaining code I wrote over 20 years ago I find that clear code is far better than clever. In the past when working with other peoples programs I often found that I had to remove large chunks of the code and replace it because the old code was not clear or maintainable.

I get the impression that you don't like the predicate conditional form
at all, then, and would rather it was stricken from the language. Yes?

I never said I wanted something stricken from the language. Much like any language I use I don't use all of the parts as there are usually more than one way to get the same results. When programming in C I didn't use all the obscure tricks to make one line programs but that didn't mean that I wanted those tricks removed from the language. In Ruby I have found that there are usually several ways to accomplish the same task and I choose to use those I can maintain, not those that will cause endless hours of time to figure out and maintain.

···

On Thu, May 31, 2007 at 11:30:30AM +0900, Michael W. Ryder wrote:

Well as I said in my original post, %$ was intended purely as a placeholder. I did also consider <= which could play an analogous role to => in hash literals but it looked even stranger. Another possibility would be:

  return f(x) if != y
  return f(x) unless == y

which would complicate the parser but is quite readable.

Ellie

Eleanor McHugh
Games With Brains

···

On 31 May 2007, at 04:46, Chad Perrin wrote:

On Thu, May 31, 2007 at 11:30:30AM +0900, Michael W. Ryder wrote:

While I realize the Ruby is not C, I think that some of the style
guidelines for C should still apply in Ruby. One of the ones that was
very important was to make each statement do only one thing. Your
example of setting a temporary variable to an amount on one line and
then testing that variable on the second line is much easier to read,
and understand, quickly than your statements like 'return %$ unless f(n)
== x'. This becomes even more important when the test is even more
convoluted such as checking for the position of a string in another
string and returning if it is in a specific location.

I'm afraid I must disagree. The only thing I find "unreadable" about
that is the complete lack of obvious association between %$ and the
source of the value it contains/labels. The composition of the
expression itself, such that the condition test is on the same line as
the rest of the action, produces absolutely zero difficulty for me.

----
raise ArgumentError unless @reality.responds_to? :reason

In Ruby there is no such thing. Every method returns something - even if it's nil.

Kind regards

  robert

···

On 03.06.2007 19:47, Eleanor McHugh wrote:

On 31 May 2007, at 06:35, Robert Dober wrote:

But maybe things should really by simple

return if x > 42
return unless (x+1)%2 == 0 # not zero? here

could probably made syntactically work (differently than now) and
return the LHS of the expression iff the expression evaluates to true
or false respectively.

Unfortunately this would greatly complicate the situation in which a return without value is intended...

> But maybe things should really by simple
>
> return if x > 42
> return unless (x+1)%2 == 0 # not zero? here
>
> could probably made syntactically work (differently than now) and
> return the LHS of the expression iff the expression evaluates to true
> or false respectively.

Unfortunately this would greatly complicate the situation in which a
return without value is intended...

That does not exist :slight_smile:
Therefore the only tread off would be to write

return nil if/unless whatever which would be an equivalent to nowadays

return if/unless

But I am not advocating this change into the language it was just an
idea in a crazy discussion :wink:

Cheers
Robert

···

On 6/3/07, Eleanor McHugh <eleanor@games-with-brains.com> wrote:

On 31 May 2007, at 06:35, Robert Dober wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

> <snip>
>> >>
>> > That is something I am surprised about, b/c the intention was to have
>> > an idiom for
>> > return it if h(x) < 10
>>
>> No, it's "return it if it < 10" with "it" being "v+1" in this case.
> Well that was the original idiom but we are looking for existing ones,
> right?

Yes, and that's why I presented what I presented. I am not sure I
understand your point here. :slight_smile:

>> > and
>> > return it_test(h(x))
>> > really is not the same, right?
>>
>> It's not the same but I believe you misread the task. it_test is just a
>> method to demonstrate the idiom in lines 2-4.
>
> Ah that's why you called the method test_..., not stupid at all :wink:
> Well I will get to understand what is going on here...
> .. eventually...
> .. potentially...
> .. maybe...
> .. hardly...

Um... It's really not that difficult.

Sure it is, actually the code is simple, I still try to grasp what is
wanted here, you see?

Hope that explains it. If not, let me know.

Well see above but never mind :slight_smile:
Thx for your time, I shall probably say what I think about all of this:
(a)
return v if ((v = 42) % 2).zero?
would be nice if it worked
(b)
I am against fancy enhancements that are purely for optimization but see above.

Cheers
Robert

···

On 5/27/07, Robert Klemme <shortcutter@googlemail.com> wrote:

On 27.05.2007 11:46, Robert Dober wrote:
> On 5/27/07, Robert Klemme <shortcutter@googlemail.com> wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

I'm afraid only compiler-side wizardry can help here.

Ruby just isn't fit to accept this syntax :stuck_out_tongue:

Is there a way in ruby to write a method that returns the caller's Binding? i.e.

def yourbinding
  #do magic stuff
  return binding
end
a = 6
yourbinding.eval("a = 8")
a #=> 8

?

Maybe using evil.rb things? The method must not be called
Kernel#binding, btw... that would be totally cheating.

Aur

···

On 5/30/07, Greg Fodor <gfodor@gmail.com> wrote:

> z = Complex[1, 1]
> p it if a(z.conj.it!) # prints 1.414..., not Complex[1, -1]
If there's anything our functional programming friends can
teach us, it's that side effects will always come back to
bite you. :slight_smile:

I like your syntax, though. Perhaps there is some wizardry
that could be done that would get the semantics of let()
but the syntax of it!() ?

That's why the fact there's no explicit, obvious connection in the
syntax between %$ and whatever it links to is a problem for readability.

···

On Thu, May 31, 2007 at 03:40:16PM +0900, Michael W. Ryder wrote:

The problem is when trying to maintain the code. Suppose you have to
change the test and it changes what is referenced by %$x or $1 or
whatever is used. Now you have to try and determine what you need to
use for the return to get the correct value. I find that harder than
having one line determine the test value and a separate line determining
what is done with that value.

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
MacUser, Nov. 1990: "There comes a time in the history of any project when
it becomes necessary to shoot the engineers and begin production."

Unfortunately for the <= idea, <= means "less than or equal to" as a
comparison operator already. I do like the readability of your return
statement syntax, though.

···

On Mon, Jun 04, 2007 at 02:46:55AM +0900, Eleanor McHugh wrote:

Well as I said in my original post, %$ was intended purely as a
placeholder. I did also consider <= which could play an analogous
role to => in hash literals but it looked even stranger. Another
possibility would be:

  return f(x) if != y
  return f(x) unless == y

which would complicate the parser but is quite readable.

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
Paul Graham: "Real ugliness is not harsh-looking syntax, but having to
build programs out of the wrong concepts."

That's true. But how many of us are in the habit of doing so explicitly with 'return nil'? Having to do that in this particular circumstance adds an extra element of surprise to the language.

Ellie

Eleanor McHugh
Games With Brains

···

On 3 Jun 2007, at 20:45, Robert Klemme wrote:

On 03.06.2007 19:47, Eleanor McHugh wrote:

On 31 May 2007, at 06:35, Robert Dober wrote:

But maybe things should really by simple

return if x > 42
return unless (x+1)%2 == 0 # not zero? here

could probably made syntactically work (differently than now) and
return the LHS of the expression iff the expression evaluates to true
or false respectively.

Unfortunately this would greatly complicate the situation in which a return without value is intended...

In Ruby there is no such thing. Every method returns something - even if it's nil.

----
raise ArgumentError unless @reality.responds_to? :reason

The _intent_ often exists, regardless of the fact that Ruby always returns a value :wink:

Ellie

Eleanor McHugh
Games With Brains

···

On 4 Jun 2007, at 06:09, Robert Dober wrote:

On 6/3/07, Eleanor McHugh <eleanor@games-with-brains.com> wrote:

On 31 May 2007, at 06:35, Robert Dober wrote:
> But maybe things should really by simple
>
> return if x > 42
> return unless (x+1)%2 == 0 # not zero? here
>
> could probably made syntactically work (differently than now) and
> return the LHS of the expression iff the expression evaluates to true
> or false respectively.

Unfortunately this would greatly complicate the situation in which a
return without value is intended...

That does not exist :slight_smile:

----
raise ArgumentError unless @reality.responds_to? :reason

We are completely on the same page with this.

Kind regards

  robert

···

On 27.05.2007 20:04, Robert Dober wrote:

On 5/27/07, Robert Klemme <shortcutter@googlemail.com> wrote:

On 27.05.2007 11:46, Robert Dober wrote:
> On 5/27/07, Robert Klemme <shortcutter@googlemail.com> wrote:
> <snip>
>> >>
>> > That is something I am surprised about, b/c the intention was to have
>> > an idiom for
>> > return it if h(x) < 10
>>
>> No, it's "return it if it < 10" with "it" being "v+1" in this case.
> Well that was the original idiom but we are looking for existing ones,
> right?

Yes, and that's why I presented what I presented. I am not sure I
understand your point here. :slight_smile:

>> > and
>> > return it_test(h(x))
>> > really is not the same, right?
>>
>> It's not the same but I believe you misread the task. it_test is just a
>> method to demonstrate the idiom in lines 2-4.
>
> Ah that's why you called the method test_..., not stupid at all :wink:
> Well I will get to understand what is going on here...
> .. eventually...
> .. potentially...
> .. maybe...
> .. hardly...

Um... It's really not that difficult.

Sure it is, actually the code is simple, I still try to grasp what is
wanted here, you see?

Hope that explains it. If not, let me know.

Well see above but never mind :slight_smile:
Thx for your time, I shall probably say what I think about all of this:
(a)
return v if ((v = 42) % 2).zero?
would be nice if it worked
(b)
I am against fancy enhancements that are purely for optimization but see above.