Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Semantics of Multiple Values

Reply
Thread Tools

Semantics of Multiple Values

 
 
Kristof Bastiaensen
Guest
Posts: n/a
 
      04-26-2004
Hi liszt,

I read on Matz' Ruby2.0 slides that the semantics
of Multiple Values will change. Are these already
decided? Here are my ideas about the subject.
I want to post it as a RCR, but I would like to have
your opinion, or criticism first. Also I am not
very familiar with the RCR mechanism.
It is already gotten to a quite large and complicated document.

Thanks,
Kristof

TITLE
Semantics of Multiple Values

ABSTRACT
This RCR describes a possible change in semantics of multiple
values, by making them equivalent to argument passing.

PROBLEM
Currently Array's are used as multiple variables, which
creates some ambiguous or unclear situations.
i.e.: a, b, c = x #where x = [1, 2, 3]

PROPOSAL

* model
=======

This proposal favors the use of multiple values as inherent
to the language, rather than a seperate data-type. It is
based on the observation that returning (multiple) values
is similar to passing arguments. This fact is even more clear
when using continuations.

for example:
x, y, z = mymethod(a, b, c)

def mymethod
return r1, r2, r3
end

would mean this

def mymethod
callcc { |cc| cc.call(2, 3, 4) }
end

#(the following isn't legal syntax, but just to show the meaning)
mymethod(a, b, c) |x, y, z|

basicly the expression:
x, y, z = <expression returning multiple arguments>
will pass the multiple arguments to the given variables like
in function argument passing

The difference with argument passing in functions are the following:
- no new scope is created, bound variable are just replaced
- there is no strict checking if the number of arguments is
correct

* new construct and method
==========================

- new construct:

because Array's are now treated different from multiple arguments
I would like to suggest the following construct
*[a, b] = [1, 2]

meaning the same as
a, b = *[1, 2]
but usefull inside blocks that pass arrays

- new method:

(for now called values)
method returning multiple values as an array

def values(*params)
params
end

values(1, 2, 4) => [1, 2, 4]

* variable assigment examples:
==============================

def multi
return 1, 2, 3
end

#multi may be replaced everywhere with (1, 2, 3)

- variable asignment

x = multi
=> x == 1

x, y = multi
=> x == 1, y == 2

x, y = multi, 3
=> x == 1, y == 3

(x, y), z = multi, 4
=> x == 1, y == 2, z == 4

(*[x, y], z), p = ([1, 2, 3], 4, 5), 6
=> x == 1, y == 2, z == 4, p == 6

* calling to functions
======================

I would recommend the following behavior:

* when passing multiple values from one function to another,
spread the values in a relaxed way (don't check the number
of parameters). When used with an explicit list, use
strict checking.

def func1(a) a end

func1(multi)
=> 1

func1(1, 2, 3)
=> error

def func2(*a) a end

func2(multi)
=> [1, 2, 3]

* when passing nested multiple variables just pass the first
element

def func3(a, b) [a, b] end

func3(multi, 4)
=> [1, 4]

func3((1, 2), 4)
=> [1, 4]
#or maybe signal error? not sure about this one

func2(multi, 4)
=> [1, 4]

func2(*values(multi), 4)
=> [1, 2, 3, 4]

* allow nested multiple values in method definitions

def func4(a, (b, c), d)
[a, b, c, d]
end

func4(1, 2, 3)
=> [1, 2, nil, 3]
#maybe raise an error?

func4(1, (2, 3), 4)
=> [1, 2, 3, 4]

func4(1, multi, 4)
=> [1, 1, 2, 4]

def func5(a, *[b, c], d)

func5(1, 2, 3)
=> [1, 2, nil, 3]

func5(1, [2, 3], 4)
=> [1, 2, 3, 4]

func5(1, (2, 3), 4)
=> [1, 2, nil, 4]
# (what will happen here is only the 2 from (2, 3) will be passed
# to func5, converted into an Array, and passed to b

* Making argument passing and multiple assignment more similar
================================================== ============

There may be other features that could be passed from arguments
passing to multiple assignment, for example hash paramaters?
Other may not be appropriate (i.e. blocks).

 
Reply With Quote
 
 
 
 
Jean-Hugues ROBERT
Guest
Posts: n/a
 
      04-26-2004
Multiple Values, Assignments and *Unifications*

This RCR is really nice.
The multiple assignment reminds me of Prolog's "unification" mechanism.
What about some further generalization ?

Why not a generalized "assign" operator ? Syntax:
assign term1, term2 [, term3 [, ...]]
And of course an "unify" operator, Syntax:
unify term1, term2 [, term3 [, ...]]

The difference between "unify" and "assign" is only when
some lvalue exists already. In that case, unify checks that
the previous value is equal to the new value. If not, no assignment
is done at all. Whereas "assign" always assigns.
Another difference is that "assign" is a short match (vs greedy for unify),
i.e. assign [a,b], [1,2,3] # 3 ignored.
i.e. assign [a,b,c], [1,2] # c ignored, not assigned anything, not even nil.

The operator = is kept as it is today,
left-terms = right_term would be equivalent to
assign [left-terms], right-term

Result
def mymethod(); return 1, [2], 3 end # Returns an Array
a, b, c = mymethod # => 3, a == 1, b == [2], c == 3
assign [a,[b]], mymethod # => 2, a == 1, b == 2, c unchanged
assign [a,[],c], mymethod # => false, [] instead of [2]
p unify [a,[2],3], mymethod # => true
p unify r, mymethod # => [1,[2],3]
p unify [a,_,_], mymethod # => 1, _ means "ignore me"

Add tail recursion optimization and you become functional.
I guess that with some callcc(), backtracking could come too.

A key benefit of this proposal is that it does not change
the current semantic of returned values. As a result it is
fully backward compatible with existing source code.

Would this solution solve the issue that your RCR solves ?

Jean-Hugues

BTW: It is often said that operator = is unusal because it does
not apply to an object. It could, we would need a BoundVariable
class, close to a Bindind, but referencing a specific variable.

At 21:24 26/04/2004 +0900, you wrote:
>Hi liszt,
>
>I read on Matz' Ruby2.0 slides that the semantics
>of Multiple Values will change. Are these already
>decided? Here are my ideas about the subject.
>I want to post it as a RCR, but I would like to have
>your opinion, or criticism first. Also I am not
>very familiar with the RCR mechanism.
>It is already gotten to a quite large and complicated document.
>
>Thanks,
>Kristof
>
>TITLE
>Semantics of Multiple Values
>
>ABSTRACT
>This RCR describes a possible change in semantics of multiple
>values, by making them equivalent to argument passing.
>
>PROBLEM
>Currently Array's are used as multiple variables, which
>creates some ambiguous or unclear situations.
>i.e.: a, b, c = x #where x = [1, 2, 3]
>
>PROPOSAL
>
>* model
>=======
>
>This proposal favors the use of multiple values as inherent
>to the language, rather than a seperate data-type. It is
>based on the observation that returning (multiple) values
>is similar to passing arguments. This fact is even more clear
>when using continuations.
>
>for example:
> x, y, z = mymethod(a, b, c)
>
> def mymethod
> return r1, r2, r3
> end
>
>would mean this
>
> def mymethod
> callcc { |cc| cc.call(2, 3, 4) }
> end
>
> #(the following isn't legal syntax, but just to show the meaning)
> mymethod(a, b, c) |x, y, z|
>
>basicly the expression:
> x, y, z = <expression returning multiple arguments>
>will pass the multiple arguments to the given variables like
>in function argument passing
>
>The difference with argument passing in functions are the following:
>- no new scope is created, bound variable are just replaced
>- there is no strict checking if the number of arguments is
> correct
>
>* new construct and method
>==========================
>
>- new construct:
>
>because Array's are now treated different from multiple arguments
>I would like to suggest the following construct
>*[a, b] = [1, 2]
>
>meaning the same as
> a, b = *[1, 2]
>but usefull inside blocks that pass arrays
>
>- new method:
>
>(for now called values)
>method returning multiple values as an array
>
>def values(*params)
> params
>end
>
>values(1, 2, 4) => [1, 2, 4]
>
>* variable assigment examples:
>==============================
>
>def multi
> return 1, 2, 3
>end
>
>#multi may be replaced everywhere with (1, 2, 3)
>
>- variable asignment
>
>x = multi
>=> x == 1
>
>x, y = multi
>=> x == 1, y == 2
>
>x, y = multi, 3
>=> x == 1, y == 3
>
>(x, y), z = multi, 4
>=> x == 1, y == 2, z == 4
>
>(*[x, y], z), p = ([1, 2, 3], 4, 5), 6
>=> x == 1, y == 2, z == 4, p == 6
>
>* calling to functions
>======================
>
>I would recommend the following behavior:
>
>* when passing multiple values from one function to another,
> spread the values in a relaxed way (don't check the number
> of parameters). When used with an explicit list, use
> strict checking.
>
> def func1(a) a end
>
> func1(multi)
> => 1
>
> func1(1, 2, 3)
> => error
>
> def func2(*a) a end
>
> func2(multi)
> => [1, 2, 3]
>
>* when passing nested multiple variables just pass the first
> element
>
> def func3(a, b) [a, b] end
>
> func3(multi, 4)
> => [1, 4]
>
> func3((1, 2), 4)
> => [1, 4]
> #or maybe signal error? not sure about this one
>
> func2(multi, 4)
> => [1, 4]
>
> func2(*values(multi), 4)
> => [1, 2, 3, 4]
>
>* allow nested multiple values in method definitions
>
> def func4(a, (b, c), d)
> [a, b, c, d]
> end
>
> func4(1, 2, 3)
> => [1, 2, nil, 3]
> #maybe raise an error?
>
> func4(1, (2, 3), 4)
> => [1, 2, 3, 4]
>
> func4(1, multi, 4)
> => [1, 1, 2, 4]
>
> def func5(a, *[b, c], d)
>
> func5(1, 2, 3)
> => [1, 2, nil, 3]
>
> func5(1, [2, 3], 4)
> => [1, 2, 3, 4]
>
> func5(1, (2, 3), 4)
> => [1, 2, nil, 4]
> # (what will happen here is only the 2 from (2, 3) will be passed
> # to func5, converted into an Array, and passed to b
>
>* Making argument passing and multiple assignment more similar
>================================================= =============
>
>There may be other features that could be passed from arguments
>passing to multiple assignment, for example hash paramaters?
>Other may not be appropriate (i.e. blocks).


-------------------------------------------------------------------------
Web: http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17



 
Reply With Quote
 
 
 
 
Kristof Bastiaensen
Guest
Posts: n/a
 
      04-26-2004
Hi,
this looks very interesting. I particulary like the hash
passing mechanism. I will add it to my RCR. It would
then work also inside method definitions:

def params({:this => a, :that => b})
[a, b]
end
params( {:this => 1, :that => 2, :dummy => 3} )
=> [1, 2]

Maybe it would be too hard to implement, or decrease
performance, but that is not for me to decide!

> Examples of possible rules:
>
> {:a=>a, :b=>b} = f(x)
> # provided f(x) returns hash, h
> # h[:a] and h[:b] assigned to a, b
>
> y.a = f(x)
> # provided f(x) returns object x with accessor a
> # assign x.a to y.a
>


This wouldn't work, because y.a = f(x) is already
valid syntax, meaning call y.a= with the value of
f(x)

> y.a, y.b = f(x)
> # provided f(x) returns object x with accessors a, b
> # assign x.a, x,b to y.a, y.b
>


Neither does this, because it would mean pass the multiple
values from f(x) to the methods y.a= and y.b=

 
Reply With Quote
 
Kristof Bastiaensen
Guest
Posts: n/a
 
      04-27-2004
Hi,

On Tue, 27 Apr 2004 03:00:23 +0900, Jean-Hugues ROBERT wrote:
> Multiple Values, Assignments and *Unifications*
>
> This RCR is really nice.
> The multiple assignment reminds me of Prolog's "unification" mechanism.
> What about some further generalization ?
>
> Why not a generalized "assign" operator ? Syntax:
> assign term1, term2 [, term3 [, ...]]
> And of course an "unify" operator, Syntax:
> unify term1, term2 [, term3 [, ...]]
>
> Result
> def mymethod(); return 1, [2], 3 end # Returns an Array
> a, b, c = mymethod # => 3, a == 1, b == [2], c == 3
> assign [a,[b]], mymethod # => 2, a == 1, b == 2, c unchanged
> assign [a,[],c], mymethod # => false, [] instead of [2]
> p unify [a,[2],3], mymethod # => true
> p unify r, mymethod # => [1,[2],3]
> p unify [a,_,_], mymethod # => 1, _ means "ignore me"
>


This looks very interesting, I hadn't thought so far.
(I also don't know so much about Prolog). From the
point of view of syntax, it would be hard to implement,
because assign [a, [b]], mymethod is already valid syntax,
and would have to make assign and unify a special construct
or operator. This may be not so clear. I cannot say much
more about it since I am not into prolog.

> A key benefit of this proposal is that it does not change
> the current semantic of returned values. As a result it is
> fully backward compatible with existing source code.


The current semantic will change anyway (see also Matz
slides about Ruby 2.0), because it has some ambiguities.
for example:

arr = [1, 2, 3]
a, b, c = arr
#currently a == 1; b == 2; c == 3
#should be a == [1, 2, 3]; b == nil; c == nil

>
> Would this solution solve the issue that your RCR solves ?
>


I think a unify operator would be a different addition than
what I described in the RCR.

> Jean-Hugues
>
> BTW: It is often said that operator = is unusal because it does
> not apply to an object. It could, we would need a BoundVariable
> class, close to a Binding, but referencing a specific variable.


Yes, I also think that would be nice. Yet another RCR?

>
>
> -------------------------------------------------------------------------
> Web: http://hdl.handle.net/1030.37/1.1
> Phone: +33 (0) 4 92 27 74 17


 
Reply With Quote
 
Dan Doel
Guest
Posts: n/a
 
      04-27-2004
Hi.

I thought since you said you don't know about Prolog, I'd say something about
it and unification, since it's interesting. Feel free to ignore this, though.

Prolog is a logic programming language, and as such, doesn't have functions
per-se. Instead, it has predicates, which are either true or false. So, for
example:

plus(0, 0, 0).
plus(0, 1, 1).
plus(1, 0, 1).

Are three predicates that are true. The first one means 0 + 0 = 0, the
second means 0 + 1 = 1, and the third means 1 + 0 = 1 (at least, it could
mean that. It could mean many things, really).

Now, with Prolog programs, you can define what's true for constants, like
above, but that doesn't get very interesting. More interesting is defining
what's true for variables. So for example, you can define Pythagorean
triples like so:

ptriple(X, Y, Z) :-
X2 is X*X,
Y2 is Y*Y
Z2 is Z*Z
Z2 is X2 + Y2.

Now, when you write

ptriple(3, 4, 5)?

Prolog unifies X2 with X*X and so on, and finally it checks that
X*X + Y*Y = Z*Z, and finds it's true, so it prints "yes" or something like
that.

However, unification is more powerful than that. With unification, you can
specify variables in your ptriple "call" and Prolog will search for values
that make it true (assuming ptriple is written correctly, which it is). So,
you can do:

ptriple(3, 4, Z).

And it will determine values of Z for which ptriple is true. Similarly, you
can do

ptriple(3, Y, 5).

And it will determine values of Y for which ptriple is true. This is quite a
bit different from all the procedural and functional languages that I
personally know, because in all of those, you have to specify which arguments
are in-parameters and which are out-parameters beforehand, but with Prolog,
if you write your predicates properly, any variable can be an in or out
parameter.

Having similar functionality in Ruby would be interesting. I don't know if
it's feasible, since unification algorithms aren't particularly easy to write,
and I don't know if it would fit with the other aspects of the language. The
proposed unification seems like a subset of the full functionality of
unification anyway, though, so that might be feasible.

The other proposition here is pattern matching, which is also in existing
programming languages. Haskell has pattern matching. For example,
lists can be built like so:

a : list

Where a is an element, list is a list, and ':' is the cons operator. However
when writing list processing routines, you don't need to take a list and
call head and such. What you can do is:

f (xs) = ...

And because of Haskell's pattern matching, if you pass something that is a
cons of an item and a list, the item gets assigned to x, and the rest of the
list gets assigned to xs. You can also do more complicated things where you
assign the whole list to a variable, but still assign heads and tails to other
variables and so on. I don't know if Matz would want to take the time to
implement such functionality, but it can be done.

Anyhow, that's it for my language theoretic tangent of the day. If any of this
was interesting, I might suggest learning a little about Prolog or Haskell.
The Art of Prolog is purportedly good (I have it, but haven't gotten around to
reading it yet), and there are several pretty good Haskell tutorials on the
internet.

Have a nice day.

- Dan


 
Reply With Quote
 
Simon Strandgaard
Guest
Posts: n/a
 
      04-27-2004
Dan Doel <(E-Mail Removed)> wrote:
[snip]
> The other proposition here is pattern matching, which is also in existing
> programming languages. Haskell has pattern matching. For example,
> lists can be built like so:
>
> a : list
>
> Where a is an element, list is a list, and ':' is the cons operator. However
> when writing list processing routines, you don't need to take a list and
> call head and such. What you can do is:
>
> f (xs) = ...
>
> And because of Haskell's pattern matching, if you pass something that is a
> cons of an item and a list, the item gets assigned to x, and the rest of the
> list gets assigned to xs. You can also do more complicated things where you
> assign the whole list to a variable, but still assign heads and tails to other
> variables and so on. I don't know if Matz would want to take the time to
> implement such functionality, but it can be done.
>


Ruby's case statement can do pattern matching.. relatively close to SML, Haskell.

server> ruby a.rb
result=61
server> ruby a.rb
result=61
server> expand -t2 a.rb
def ackerman(m, n)
case
when m==0: n+1
when n==0: ackerman(m-1, 1)
else ackerman(m-1, ackerman(m, n-1))
end
end
result = ackerman(3, 3)
puts "result=#{result}"
server>

--
Simon Strandgaard



 
Reply With Quote
 
Kristof Bastiaensen
Guest
Posts: n/a
 
      04-27-2004
Hi, thanks for the explanations!

> Having similar functionality in Ruby would be interesting. I don't know
> if it's feasible, since unification algorithms aren't particularly easy
> to write, and I don't know if it would fit with the other aspects of the
> language. The proposed unification seems like a subset of the full
> functionality of unification anyway, though, so that might be feasible.


I don't think it would be feasible. Ruby would have to conclude
from
X2 = Z * Z with X2 == 25
that Z == 5. It cannot have this information, because * as a
method could mean anything.

>
> The other proposition here is pattern matching, which is also in existing
> programming languages. Haskell has pattern matching. For example,
> lists can be built like so:
>
> a : list
>
> Where a is an element, list is a list, and ':' is the cons operator. However
> when writing list processing routines, you don't need to take a list and
> call head and such. What you can do is:
>
> f (xs) = ...
>


I would propose something like:
def mymethod(*[a, *b])
[a, b]
end
mymethod [1, 2, 3, 4]
=> [1, [2, 3, 4]]

It would only be a subset of pattern matching, but interesting
on its own.

We could use := as a unify operator, it would be a combination
of comparison and assignment.
I have added these to my RCR.

 
Reply With Quote
 
Kristof Bastiaensen
Guest
Posts: n/a
 
      04-27-2004
Hi, here is my update RCR.
It adds a unify operator := , multiple variables
comparison, and some more goodies (

TITLE

Semantics of Multiple Values

ABSTRACT

This RCR describes a possible change in semantics of multiple values,
by making them equivalent to argument passing.

PROBLEM

Currently Array's are used as multiple variables, which creates some
ambiguous or unclear situations. i.e.:

a, b, c = x #where x = [1, 2, 3]

PROPOSAL

* model
========

This proposal favors the use of multiple values as inherent to the
language, rather than a separate data-type. It is based on the
observation that returning (multiple) values is similar to passing
arguments. This is even more apparent when using continuations.

for example:

def mymethod(a, b)
return a + 1, b + 2, a
end

x, y, z = mymethod(1, 2)

would mean this

def mymethod(a, b)
callcc { |cc| cc.call(a + 1, b + 2, a) }
end

#(the following isn't legal syntax, but just to show the meaning)
mymethod(1, 2) |x, y, z|

basicly the expression:

x, y, z = <expression returning multiple arguments>

will pass the multiple arguments to the given variables like in
function argument passing.

The difference with argument passing in functions are the following:


* no new scope is created, bound variable are just replaced

* there is no strict checking if the number of arguments is correct

* new constructs and method
============================

- new constructs:
------------------
because Array's are now treated different from multiple arguments I
would like to suggest the following construct:

*[a, b] = [1, 2]

meaning the same as

a, b = *[1, 2]

but useful inside blocks that pass arrays. Optionally allow:

*[a, *b] = [1, 2, 3]
=> a == 1, b == [2, 3]

or perhaps with hashes:

*{:a => c, :b => d} = {a: 1, b: 2}
=> c == 1; b == 2

*{:a => c, *b} = {a: 1, b: 2, c: 3}
=> c = 1, b = {:b => 2, :c => 3}

these constructs would work both in argument passing and variable
assignment.

- new method:
--------------
(for now called values) method returning multiple values as an array

def values(*params)
params
end

values(1, 2, 4) => [1, 2, 4]


* variable assigment examples:
===============================

def multi
return 1, 2, 3
end

#multi may be replaced everywhere with (1, 2, 3)

x = multi
=> x == 1

x, y = multi
=> x == 1, y == 2

x, y = multi, 3
=> x == 1, y == 3

(x, y), z = multi, 4
=> x == 1, y == 2, z == 4

(*[x, y], z), p = ([1, 2, 3], 4, 5), 6
=> x == 1, y == 2, z == 4, p == 6

* calling to functions
=======================

I would recommend the following behavior:

* when passing multiple values from one function to another, spread
the values in a relaxed way (don't check the number of parameters).
When used with an explicit list, use strict checking.

def func1(a) a end

func1(multi)
=> 1

func1(1, 2, 3)
=> error

def func2(*a) a end

func2(multi)
=> [1, 2, 3]

def func3(a, b) [a, b] end

func3(multi)
=> [1, 2]

* when passing nested multiple variables just pass the first element

func3(multi, 4)
=> [1, 4]

func3((1, 2), 4)
=> [1, 4]
#or maybe signal error? not sure about this one

func2(multi, 4)
=> [1, 4]

func2(*values(multi), 4)
=> [1, 2, 3, 4]

* allow nested multiple values in method definitions

def func4(a, (b, c), d)
[a, b, c, d]
end

func4(1, 2, 3)
=> [1, 2, nil, 3]
#maybe raise an error?

func4(1, (2, 3), 4)
=> [1, 2, 3, 4]

func4(1, multi, 4)
=> [1, 1, 2, 4]

def func5(a, *[b, c], d)

func5(1, 2, 3)
=> [1, 2, nil, 3]

func5(1, [2, 3], 4)
=> [1, 2, 3, 4]

func5(1, (2, 3), 4)
=> [1, 2, nil, 4]
# (what will happen here is only the 2 from (2, 3) will be passed
# to func5, converted into an Array, and passed to b

* Making argument passing and multiple assignment more similar
================================================== =============

There may be other features of multiple assignment that could be taken
from argument passing, for example hash parameters(?). Other may not
be appropriate (i.e. blocks).

example:

def func6
return 4, b: 5, c:6
end

a, b:, **keys = func6
=> a == 4; b == 5; keys == {:c=>6}

* Comparing multiple values
============================

Multiple values may be compared using comparison operators. For
example:

a, b, (c, d), e == 1, 2, (3, 4), 5

would mean

a == 1 && b == 2 && c == 3 && d == 4 && e == 5

with the exception that in the first, all the expressions will be
evaluated. It would return false if the number of arguments to the left
aren't equal to the ones to the right.

It would be also useful to be able to compare with the operator ===, so
multiple values can be compared inside case statements. When
comparing one value with multiple values, return true if at least on
matches.

1 === (1, 2, 3)
=> true
#same as 1 === 1 or 1 === 2 or 1 === 3

case a, b
when 1, 2
puts "is 1 and 2"
when (2, 3), 4
puts "is (2 or 3) and 4"
end

* Unify operator
=================

This section descibes a unify operator, that works like a combination
of comparison and assignment (similar to unify in Prolog). The
expression

a, b, c := multi

would assign the lefthand values, if unbound (or nil?) to the
corresponding righthand value, and if bound (or an immediate value)
compare if they are equal. If one of the comparisons would return false,
no assignment will be done.

examples:

a, b, c := 1, 2
=>true (a == 1, b == 2, c == unbound or nil)

a, b := 1, 3
=>false (a == 1, b == 2, c == unbound or nil)

a, c := 1, 2
=>true (a == 1, b == 2, c == 2)

def amethod
return true, 1, 2,
end
true, x, y := amethod
=>true (x == 1, y == 2)

ANALYSIS

The changes I proposed here provide a consistent way of using multiple
values, by using (mostly) the same semantic model for assignment as for
argument passing, without losing any power to the language. The major
drawback is that programs written using the old semantics may not work
correctly, (but the current behavior will change anyway?). It also
descibes some other extensions to the language that may or may not be
useful.

IMPLEMENTATION

These changes will have to be made to the core of the language. Some
features I described above may be to hard to implement or decrease
performance (nested multiple values in method definitions,
assigning variables from hash elements), and therefor disallowed.
 
Reply With Quote
 
Yukihiro Matsumoto
Guest
Posts: n/a
 
      04-27-2004
Hi,

In message "Re: Semantics of Multiple Values (updated RCR)"
on 04/04/27, Kristof Bastiaensen <(E-Mail Removed)> writes:

|TITLE
|
|Semantics of Multiple Values

Interesting, but I'm afraid this one is too big (and too complex)
change. I'd like to see a language with this semantics though.

|*[a, *b] = [1, 2, 3]
|=> a == 1, b == [2, 3]
|
|or perhaps with hashes:
|
|*{:a => c, :b => d} = {a: 1, b: 2}
|=> c == 1; b == 2
|
|*{:a => c, *b} = {a: 1, b: 2, c: 3}
|=> c = 1, b = {:b => 2, :c => 3}

| func3((1, 2), 4)
| => [1, 4]
| #or maybe signal error? not sure about this one

Making (1,2) as values is not a good idea. Perhaps we should prepare
"array to values" converter (opposite of your "values" method).

| func2(*values(multi), 4)
| => [1, 2, 3, 4]

I'm still against argument splat in the middle of actual argument
list. It's not consistent with formal argument list, where splat is
only allowed at the end.

|There may be other features of multiple assignment that could be taken
|from argument passing, for example hash parameters(?). Other may not
|be appropriate (i.e. blocks).
|
|example:
|
|def func6
| return 4, b: 5, c:6
|end
|
|a, b:, **keys = func6
|=> a == 4; b == 5; keys == {:c=>6}

I just don't feel right about this. Maybe arguments and return values
are different beasts in my brain, even though continuation tells us
their similarity.

|* Comparing multiple values
|* Unify operator

I have to confess I couldn't understand those two proposals, how they
behave, and how they are useful.

matz.


 
Reply With Quote
 
Kristof Bastiaensen
Guest
Posts: n/a
 
      04-27-2004
Hi,

On Tue, 27 Apr 2004 23:39:24 +0900, Yukihiro Matsumoto wrote:

> | func3((1, 2), 4)
> | => [1, 4]
> | #or maybe signal error? not sure about this one
>
> Making (1,2) as values is not a good idea.


Yes, I agree that nesting values would be overcomplicating things,
and is probably too hard to implement.

> Perhaps we should prepare
> "array to values" converter (opposite of your "values" method).
>


Isn't * an array to values converter?
(like in method(1, *[2, 3, 4]))?

> | func2(*values(multi), 4)
> | => [1, 2, 3, 4]
>
> I'm still against argument splat in the middle of actual argument
> list. It's not consistent with formal argument list, where splat is
> only allowed at the end.
>


Sorry, I overlooked this one.

> |There may be other features of multiple assignment that could be taken
> |from argument passing, for example hash parameters(?). Other may not
> |be appropriate (i.e. blocks).
> |
> |example:
> |
> |def func6
> | return 4, b: 5, c:6
> |end
> |
> |a, b:, **keys = func6
> |=> a == 4; b == 5; keys == {:c=>6}
>
> I just don't feel right about this. Maybe arguments and return values
> are different beasts in my brain, even though continuation tells us
> their similarity.
>


Yes, it is perhaps more proof of concept than really practical.
(Being obliged to choose your variable naming wouldn't surely be
a good idea). Some other constructs may be more practical.
When Arrays are not the same as multiple values, the following
will not work:
a = [[1, 2], [3, 4]]
a.each { |a, b| #something useful here ...
}
that's why my idea was to have to following construct:
a.each { |*[a, b]| #something useful ...
}
and similarly:
*[a, b] = a[1]

> |* Comparing multiple values
> |* Unify operator
>
> I have to confess I couldn't understand those two proposals, how they
> behave, and how they are useful.
>
> matz.


The idea of comparing multiple values would be a kind of
syntactic sugar.
Instead of writing
x == 1 && y == 2
you could write
x, y == 1, 2
(which looks much clearer in my eyes).
In concrete it would evaluate all the expressions, and then
compare them one by one. The first on the left will be compared with
the first on the right, the second with the second, and so on.
When all return true, evaluate to true.

When comparing with ===, one could compare with multiple
values:
if (1, 3, 4..5) === x
<...>
end
that would work like it does in case statements:
case x
when 1, 3, 4..5
<...>
end

About the unify operator, I am not so sure myself it is
really usefull. I just put it here for discussion.

Thanks,
Kristof
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
assigning multiple hash values to multiple variables Patrick Perl Misc 5 05-03-2006 05:06 PM
showing multiple values from multiple db rows in a DropDownList Schultz ASP .Net 1 02-14-2005 12:38 AM
it's all about semantics =?Utf-8?B?RGltaXRyaXMgUGFudGF6b3BvdWxvcw==?= ASP .Net 2 07-14-2004 08:19 AM
Semantics extractor Luigi Donatello Asero HTML 5 02-14-2004 07:10 PM
destructor / semantics of delete this Alexander Stippler C++ 6 08-20-2003 03:27 PM



Advertisments