A very half-baked idea: setting local variables

I'm sure this nonexistent feature is not in great demand, but there have
been different times that I (and other people) have wanted it.

This is not a "really serious" proposal, but I wanted to see what other
people's comments were about lengthy multiple assignments and
how to deal with them.

Sometimes I wish I had an alternative way to do assignment.

Example:

  foo, bar, baz, alpha, beta, gamma, fred, bill, joey = *values

In a case like that, my eye has to scan a long way to the right
before finding the equal sign and grasping that this is a multiple
assignment.

I like this better:

  vars = [:foo, :bar, :baz, :alpha, :beta, :gamma, :fred, :bill, :joey]
  assign values, vars

Note that this wouldn't be a method call (like alias_method) but
a keyword (like alias) unless "binding of caller" was permitted...
which is another thing I've wanted but I suppose will never
happen.

Comments, questions, projectiles?

Hal

At the moment there is no other way I am aware of to introduce local
variables _at runtime_. While you can do things like eval("foo = 123") the
remaining code won't be using the local variable.

$ ruby -e 'b=binding;eval("x=10", b);puts x'
-e:1:in `<main>': undefined local variable or method `x' for main:Object
(NameError)
$ ruby -e 'b=binding;eval("x=10", b);eval("puts x", b)'
10

How about

data = {}
[:foo, :bar, :baz, :alpha, :beta, :gamma, :fred, :bill,
:joey].each_with_index do |s,i|
  data[s] = values[i]
end

puts data[:baz]

or even

data = [:foo, :bar, :baz, :alpha, :beta, :gamma, :fred, :bill,
:joey].each_with_index.each_with_object {} do |(s,i), d|
  d[s] = values[i]
end

?

Cheers

robert

···

On Mon, Jul 8, 2013 at 11:06 PM, Hal Fulton <rubyhacker@gmail.com> wrote:

I'm sure this nonexistent feature is not in great demand, but there have
been different times that I (and other people) have wanted it.

This is not a "really serious" proposal, but I wanted to see what other
people's comments were about lengthy multiple assignments and
how to deal with them.

Sometimes I wish I had an alternative way to do assignment.

Example:

  foo, bar, baz, alpha, beta, gamma, fred, bill, joey = *values

In a case like that, my eye has to scan a long way to the right
before finding the equal sign and grasping that this is a multiple
assignment.

I like this better:

  vars = [:foo, :bar, :baz, :alpha, :beta, :gamma, :fred, :bill, :joey]
  assign values, vars

Note that this wouldn't be a method call (like alias_method) but
a keyword (like alias) unless "binding of caller" was permitted...
which is another thing I've wanted but I suppose will never
happen.

Comments, questions, projectiles?

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

Hal Fulton wrote in post #1114777:

Note that this wouldn't be a method call (like alias_method) but
a keyword (like alias) unless "binding of caller" was permitted...
which is another thing I've wanted but I suppose will never
happen.

Comments, questions, projectiles?

Yeah, I agree with Robert, there's no need to dynamically create local
variables, just use a hash (dynamically created keys are fine). And my
initial gut response is: if you're writing that many variables on the
left hand side of an assignment, with a single array on the right,
there's probably something wrong with the architecture.

My other counter-proposal is: hit enter. If the line is too long,
develop a syntactic signature for the pattern. For example:

    foo, bar, baz, alpha, beta,
        gamma, fred, bill, joey = *values

(i.e. lining up the rightmost column, so it's clear that all wrapped
lines lead to the single assignment operator). Still not great, but at
least the line isn't absurdly long, and you don't have to scan as far to
see the '='

Finally, as a bike-shedding nit-pick: if it were a keyword, convention
suggests there'd be no comma; and I think putting the destinations on
the right is a bit confusing. So if I had to choose, I'd go for:

    assign %I[a b c] values

But again, that's a big "if", and all in all I'm not too keen on the
idea of dynamically creating local variables.

···

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

Once you get to that many local variables I'm sure you could define a
class to handle the behaviour you want.
Once you start using variables where the names are important, you'd be
better of with a Hash. That's the whole point of Hashes.

···

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

Hal Fulton wrote in post #1114777:
>
> Note that this wouldn't be a method call (like alias_method) but
> a keyword (like alias) unless "binding of caller" was permitted...
> which is another thing I've wanted but I suppose will never
> happen.
>
> Comments, questions, projectiles?

Yeah, I agree with Robert, there's no need to dynamically create local
variables, just use a hash (dynamically created keys are fine). And my
initial gut response is: if you're writing that many variables on the
left hand side of an assignment, with a single array on the right,
there's probably something wrong with the architecture.

That situation frequently occurs when reading data e.g. from CSV files. If
the file has that many columns it makes sense to have local variables for
them to ease handling. OTOH then you probably use something like

CSV.foreach "a.csv" do |foo, bar, baz, alpha, beta|
  puts "foo is #{foo}"
end

Or one defines a Struct and puts values in there instead of having them in
an Array.

My other counter-proposal is: hit enter. If the line is too long,

develop a syntactic signature for the pattern. For example:

    foo, bar, baz, alpha, beta,
        gamma, fred, bill, joey = *values

(i.e. lining up the rightmost column, so it's clear that all wrapped
lines lead to the single assignment operator). Still not great, but at
least the line isn't absurdly long, and you don't have to scan as far to
see the '='

I like that approach.

Finally, as a bike-shedding nit-pick: if it were a keyword, convention
suggests there'd be no comma; and I think putting the destinations on
the right is a bit confusing. So if I had to choose, I'd go for:

    assign %I[a b c] values

But again, that's a big "if", and all in all I'm not too keen on the
idea of dynamically creating local variables.

I forgot to mention: I do not see the original issue as such a big one, so
my general bias would be against going through some hoops just to avoid
lengthy left hand sides. I don't have them that often and if I have it
does not bother me that much.

Kind regards

robert

···

On Tue, Jul 9, 2013 at 1:14 AM, Matthew Kerwin <lists@ruby-forum.com> wrote:

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

I agree with 95% of the comments people made in this thread.

I think the "proper" solution in my situation(s) is to define a class
or at least a struct.

FWIW, I see this mostly in code that is not my own. I don't usually
use length multiple assignment like that (and I *do* break up the
lines whether I wrote it originally or not).

Cheers,
Hal

···

On Tue, Jul 9, 2013 at 3:08 AM, Joel Pearson <lists@ruby-forum.com> wrote:

Once you get to that many local variables I'm sure you could define a
class to handle the behaviour you want.
Once you start using variables where the names are important, you'd be
better of with a Hash. That's the whole point of Hashes.

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

Hal Fulton wrote in post #1114777:

Note that this wouldn't be a method call (like alias_method) but
a keyword (like alias) unless "binding of caller" was permitted...
which is another thing I've wanted but I suppose will never
happen.

...

My other counter-proposal is: hit enter. If the line is too long,
develop a syntactic signature for the pattern. For example:

     foo, bar, baz, alpha, beta,
         gamma, fred, bill, joey = *values

Or, taking Matthew's suggestion a bit further:

     foo, bar, baz, alpha, beta,
         gamma, fred, bill, joey,
       = *values

A line beginning with an equals sign is visually conspicuous.

···

On 07/08/2013 04:14 PM, Matthew Kerwin wrote: