Semantics of Multiple Values

Discussion in 'Ruby' started by Kristof Bastiaensen, Apr 26, 2004.

  1. 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).
    Kristof Bastiaensen, Apr 26, 2004
    #1
    1. Advertising

  2. 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,], 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
    Jean-Hugues ROBERT, Apr 26, 2004
    #2
    1. Advertising

  3. 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=
    Kristof Bastiaensen, Apr 27, 2004
    #3
  4. 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,], 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, ], 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
    Kristof Bastiaensen, Apr 27, 2004
    #4
  5. Kristof Bastiaensen

    Dan Doel Guest

    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 (x: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
    Dan Doel, Apr 27, 2004
    #5
  6. Dan Doel <> 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 (x: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
    Simon Strandgaard, Apr 27, 2004
    #6
  7. 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 (x: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.
    Kristof Bastiaensen, Apr 27, 2004
    #7
  8. Re: Semantics of Multiple Values (updated RCR)

    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.
    Kristof Bastiaensen, Apr 27, 2004
    #8
  9. Re: Semantics of Multiple Values (updated RCR)

    Hi,

    In message "Re: Semantics of Multiple Values (updated RCR)"
    on 04/04/27, Kristof Bastiaensen <> 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.
    Yukihiro Matsumoto, Apr 27, 2004
    #9
  10. Re: Semantics of Multiple Values (updated RCR)

    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
    Kristof Bastiaensen, Apr 27, 2004
    #10
  11. Re: Semantics of Multiple Values (updated RCR)

    Yukihiro Matsumoto wrote:
    > Hi,


    Moin!

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


    I think both should be allowed. Both func2(*(values + [4])) manual
    argument handling in methods are a stark contrast in ugliness to their
    respective end-of-argument-list counterparts.

    I also think that all this looks even weirder in Array construction. I
    think this case would be a good one to support:

    ary = [1, 2, 3]
    [:foo, *ary, :bar, *ary, :qux]

    However I don't think that there should be support for multiple
    splat-arguments in method argument lists. That would feel too unnatural.
    This would be a small asymmetry.

    Regards,
    Florian Gross
    Florian Gross, Apr 27, 2004
    #11
  12. Re: Semantics of Multiple Values (updated RCR)

    At 23:39 27/04/2004 +0900, you wrote:
    >|* 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.


    I have some Prolog background and I believe Prolog is the
    language where unification is central.

    First, I have to say that what I proposed is a "poor man's unification".
    Not that its value is low, only it does not turn Ruby into Prolog.

    Q. So, what is a "poor man's unify".
    A. Well... it is Unification. But without a key aspect of it: Backtracking.

    Q. Backtracking ?
    A. Backtracking is what happen when a function can return many values,
    once a time, like a generator if you wish. So let's forget about that.

    What remains is a mechanism that does two things at once:
    - comparison
    - assignment

    Q. You mean, I can have my cake and eat it too ?
    A. Cool, isn't it ?

    Comparison: ==
    We know what it is already. It depends either on the identity of objects
    or on their value. Let's skip the easy one.

    Comparison by value:
    For scalar type, it's easy, "a" is "a" and 1 is 1.
    For collection, it's slightly more complex. You compare (note the
    recursivity introduced here) each element of the collections.

    Q. That's not exactly true, .==() is called.
    A. True. Let's assume that the unification algorithm walk the collections
    itself, calling some .unify() instead.

    So far, so good, known stuff.

    Now, Assignment: =
    Assignment is about setting the value of a Variable.
    Before the assignment, there exists 2 cases:
    - The variable exists already. It is "Bound" to something
    - The variable does not exit. It is "Free"
    After the assignment the variable is bound to some value.

    Finally, Comparison + Assignment:
    Let's assume that, in addition to a scalar and collection, a
    value can be a reference to a variable (not the case in Ruby today).

    Q. Then, what happens with comparison ?
    A. That's easy:
    - For a variable that exists already, you pick it's value and
    you use it to do the comparison. "Bound" case.
    - For a variable that does not already exists, it is even easier,
    you assume that the comparison succeed and, as a side effect,
    you "create" the variable with the value it was compared against.

    Q. That's it !
    A. Yes !

    Q. Now, what about the consequences/impacts on Ruby ?

    A. First and paramount is that when building a value, in the context
    of a "Comparison + Assignment", you cannot proceed as usual. i.e.
    unify [a,b], [c,d] is not like [a,b] == [c,d].

    Q. OK. How ?
    A. When you evaluate the later (==), you build values getting rid of the
    variables, i.e. you use the value of the variable in place of the
    variable itself.

    Whereas with unify, you don't. Instead, whenever there is a variable,
    you keep it.

    Q. How is that possible ?
    A. Well, it is... you need something that does not exists in Ruby so far,
    an object that describes a variable. In such a way that, instead
    of using the variable's value, you reference the variable itself.

    Q. In C, this is &var, the "address of var", similar ?
    A. Yes, pretty much the same.

    So, if a is 1, b is 2... then
    [a,b] == [c,d] is about comparing [1,2] with [3,4] and...
    unify [a,b], [c,d] is about [&a,&b] and [&c,&d] (using C's syntax)

    That's an additional level of indirection.

    Q. OK. Nice. But where is it useful ?
    A. Very often ! It is already there in Ruby actually !

    Q. No kidding ?
    A. No, look.

    def f( a, b, c ); ... end
    When f is invoked, some unification occur:
    unify f's args, [a,b,c]

    a, b, c = f()
    When assignment with multiple values occur:
    unify [a,b,c], f() # Q. Almost... what if f() returns [1,2] ?
    # Q. What if a, b or c already exists ?

    p = proc( { |a,b,c| ... }
    p.call( 1, 2, 3)
    When Proc get their parameters:
    unify [a,b,c], proc's actual parameters

    A. "unify" is there but not exactly with the same semantic:
    - Assignment always occur, even if variable is already bound.
    - nil is assigned to the variable when there is no better value.
    That behaviour is what I call "assign", versus "unify".

    "unify" and "assign" work even better if a new type of
    value is introduced (in addition to the one introduced already,
    the one that is a & reference to a variable).

    The new type is "FreeClass", much like TrueClass. That is
    a Singleton too.

    Q. What is it for ?
    A. a = FreeClass.instance() is the way to "free" the "bound"
    variable named "a". Shorthand: a = free

    Now, some examples, explained.

    def test()
    unify a, 1
    p a # => 1, a was free, now it is bound
    a = free
    p a # free, a is free again
    unify a, 2
    p a # => 2, a was free
    unify a, 3
    p a # => 2, a was bound, unify failed.
    a = free
    unify [a,b], [] # Fails (evaluate to false)
    unify [a,b], [1,2]
    p a, b # => 1 2, unify succeeded.
    unify [free,b], [1,2] # Succeeds
    unify [free,b], [1,3] # Fails
    unify [free,b], [1,c] # Succeeds
    p c # => 2... it works both ways
    a = b = c = free
    unify [a,b], [1,2,3]
    p a, b # nil nil, unify failed
    assign [a,b], [1,2,3]
    p a, b # 1, 2, assign is more tolerant
    assign [2,b], [1,3]
    p b # 2, assign failed, no assignments done
    end

    I hope that this explanation, way too long, gives you
    some idea about how powerful an "assign" and "unify"
    operators could be and how close they are to what
    already exists.

    Nota: *, like in f( *args), makes them even more powerful !

    Yours,

    Jean-Hugues
    Jean-Hugues ROBERT, Apr 27, 2004
    #12
  13. Re: Semantics of Multiple Values (updated RCR)

    Jean-Hugues ROBERT wrote:
    > Q. So, what is a "poor man's unify".
    > A. Well... it is Unification. But without a key aspect of it: Backtracking.


    On the other hand, it would probably be reasonably easy to implement
    using continuations if one really wanted to.
    Linus Sellberg, Apr 27, 2004
    #13
  14. Re: Semantics of Multiple Values (updated RCR)

    Hi,

    On Wed, 28 Apr 2004 04:51:59 +0900, Jean-Hugues ROBERT wrote:
    >
    > "unify" and "assign" work even better if a new type of
    > value is introduced (in addition to the one introduced already,
    > the one that is a & reference to a variable).
    >
    > The new type is "FreeClass", much like TrueClass. That is
    > a Singleton too.
    >
    > Q. What is it for ?
    > A. a = FreeClass.instance() is the way to "free" the "bound"
    > variable named "a". Shorthand: a = free


    This type already exists: NilClass, with as only
    instance nil. In fact nil is always used for unbound variables.
    Whenever a variable isn't bound, it evaluates to nil, for all
    variables (global, object) except local. Local variables are
    the only ones that can raise an error, the reason for this is
    that local variables and methods or interchangeable. Whenever
    Ruby sees a local variable that didn't have an assignment before,
    it treats it as a method call. When at runtime it executes the
    method, and cannot find it, it will give an error.

    I would suggest using := as a unification operator. Ruby could
    then always see that what is before the operator are variables.
    It would treat nil as the unbound.
    I am still not really convinced of the practical use of this
    operator. I can see one usage, as initialization:

    a := 0 #meaning a = 0 if (a == nil).

    perhaps the following

    def search_data
    some_operation
    return succeed, value1, value2
    end

    a, b = nil
    if true, a, b := search_data
    <use a, b>
    end

    #but you may as well use
    succes, a, b = search_data
    if(succes)
    <use a, b>
    end

    There may be other real world practical uses, but I cannot think
    of any.
    Any suggestions?
    Kristof Bastiaensen, Apr 27, 2004
    #14
  15. Re: Semantics of Multiple Values (updated RCR)

    Hi,

    In message "Re: Semantics of Multiple Values (updated RCR)"
    on 04/04/28, Kristof Bastiaensen <> writes:

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

    I don't think so, even with your proposal. If * (splat operator) is
    an array to values converter,

    def func1(a,b)
    [a,b]
    end
    func1(1, *[2, 3, 4])

    should give [1,2], unless values work like LIST in Perl.

    |> |* Comparing multiple values
    |> |* Unify operator
    |>
    |> I have to confess I couldn't understand those two proposals, how they
    |> behave, and how they are useful.
    |
    |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).

    Not for my eyes. YMMV.
    I don't feel right to mix comparison operands x, 1, and y, 2.

    matz.
    Yukihiro Matsumoto, Apr 28, 2004
    #15
  16. Re: Semantics of Multiple Values (updated RCR)

    At 06:54 28/04/2004 +0900, you wrote:
    >Hi,
    >On Wed, 28 Apr 2004 04:51:59 +0900, Jean-Hugues ROBERT wrote:
    > > "unify" and "assign" work even better if a new type of
    > > value is introduced (in addition to the one introduced already,
    > > the one that is a & reference to a variable).
    > >
    > > The new type is "FreeClass", much like TrueClass. That is
    > > a Singleton too.
    > >
    > > Q. What is it for ?
    > > A. a = FreeClass.instance() is the way to "free" the "bound"
    > > variable named "a". Shorthand: a = free

    >
    >This type already exists: NilClass, with as only
    >instance nil. In fact nil is always used for unbound variables.
    >Whenever a variable isn't bound, it evaluates to nil, for all
    >variables (global, object) except local. Local variables are
    >the only ones that can raise an error, the reason for this is
    >that local variables and methods or interchangeable. Whenever
    >Ruby sees a local variable that didn't have an assignment before,
    >it treats it as a method call. When at runtime it executes the
    >method, and cannot find it, it will give an error.


    nil ? Not quite. nil is a valid value for a bound variable.
    unify nil, 1 # fails

    >I would suggest using := as a unification operator. Ruby could
    >then always see that what is before the operator are variables.
    >It would treat nil as the unbound.


    Makes sense (but a binary unify operator is more like =~= than
    :=, because it works both ways, a := b eqv b := a).

    syntax unify x, z makes sense too because one can also unify x, y, z

    BTW: what is *after* the operator is also variables (sometimes).
    Having the variables on the left side is just a trick to put the
    emphasis on the fact that statement is more like assignment than
    comparison.

    >I am still not really convinced of the practical use of this
    >operator. I can see one usage, as initialization:


    inits ? that's right, specially considering that Ruby current
    initialization semantic is already a subset of unify.

    >a := 0 #meaning a = 0 if (a == nil).


    No. Should be:
    a := 0 # meaning a = 0 if a does not exists already.
    I would prefer a =~= 0 however, or unify a, 0

    >perhaps the following
    >
    >def search_data
    > some_operation
    > return succeed, value1, value2
    >end
    >
    >a, b = nil
    >if true, a, b := search_data
    > <use a, b>
    >end


    another example:
    if true, "a", b =~= seach_data then
    <use b>
    end

    >#but you may as well use
    >succes, a, b = search_data


    That is an example where one can see that something very
    similar to a more generalized unify already exists in Ruby.
    i.e. success, a, b = seach_data eqv unify [success, a, b], seach_data
    I am proposing to enhance slightly what already exists.

    >if(succes)
    > <use a, b>
    >end


    Yes, but:
    success, a, b = seach_data
    if success and a == "a"
    <use b>
    end
    is becoming verbose compared to:
    if true, "a", b =~= seach_data
    <use b>
    end

    >There may be other real world practical uses, but I cannot think
    >of any.
    >Any suggestions?


    Plenty. Where ever there is a combination of comparison and
    assignment, unify (and/or =~=) will be less verbose.


    Back to nil & free:
    If you want to avoid a FreeClass, at least you need a way to free
    bound variables. I suppose that a there is already enough in Ruby
    today to:
    1) Check if a variable already exists
    2) "delete" it

    I also suppose it is possible to prototype unify/assign today in
    Ruby. I may do it. However, a user level implementation is not
    going to look very nice (not mentioning performances). That is
    why some support at the syntax level would help. Additionnaly,
    a user level unify will not integrate well with the existing
    stuff about multiple assignments and parameters passing.

    def test()
    # unify [a,b], [1,2]
    unify [ ref{:a}, ref{:b} ], [1,2]
    a = Free
    unify ref{:a}, ref{:b}
    end

    # def mymethod( a, (b, c) ) # but using user level unify
    def mymethod( *args )
    unify [ref{:a},[ref{:b},ref{:c}]], args
    ...
    end

    Have a look at http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc
    for a definition of a Reference class and a ref{var_name} factory method.

    Yours,

    Jean-Hugues


    -------------------------------------------------------------------------
    Web: http://hdl.handle.net/1030.37/1.1
    Phone: +33 (0) 4 92 27 74 17
    Jean-Hugues ROBERT, Apr 28, 2004
    #16
  17. Re: Semantics of Multiple Values (updated RCR)

    At 08:53 28/04/2004 +0900, you wrote:
    >Hi,
    >
    >In message "Re: Semantics of Multiple Values (updated RCR)"
    > on 04/04/28, Kristof Bastiaensen <> writes:
    >
    >|Isn't * an array to values converter?
    >|(like in method(1, *[2, 3, 4]))?
    >
    >I don't think so, even with your proposal. If * (splat operator) is
    >an array to values converter,
    >
    > def func1(a,b)
    > [a,b]
    > end
    > func1(1, *[2, 3, 4])
    >
    >should give [1,2], unless values work like LIST in Perl.


    I tried it. It raises a wrong number of argument error (4 for 2).
    However:
    def func1(a,b,*rest)
    [a,b]
    end
    func1(1, *[2, 3, 4])
    do give [1,2]

    >|> |* Comparing multiple values
    >|> |* Unify operator
    >|>
    >|> I have to confess I couldn't understand those two proposals, how they
    >|> behave, and how they are useful.
    >|
    >|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).
    >
    >Not for my eyes. YMMV.


    Not obvious to me either. If feel like I would rather write
    if [x, y] == [1, 2] then
    OTOH, x, y == 1, 2 may help avoid building 2 Array objects and
    speed things up (an optimizing compiler could do that too).

    >I don't feel right to mix comparison operands x, 1, and y, 2.
    >
    > matz.


    I agree.
    I feel like extending the syntax is worthwhile if the added
    benefit is really significant.

    Rather than allowing x, y == 1, 2, I would prefer a more
    general x, y =~= 1, 2 whose semantic is richer due to the
    fact that it may end up assigning either x, y or both if
    they don't exist already (or if they were unbound/freed).

    Yours,

    Jean-Hugues


    -------------------------------------------------------------------------
    Web: http://hdl.handle.net/1030.37/1.1
    Phone: +33 (0) 4 92 27 74 17
    Jean-Hugues ROBERT, Apr 28, 2004
    #17
  18. Re: Semantics of Multiple Values (updated RCR)


    >Have a look at http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc
    >for a definition of a Reference class and a ref{var_name} factory method.


    I like that code but I am looking for a better looking syntax.
    ref{:a} is quite short, but I am looking for something shorter.

    Ideally &a, but that is already valid syntax in Ruby for something else.

    r{:a} is shorter, but pollutes Kernel space with a global r() method.

    Is there an unary operator that can be redefined ?

    Yours,

    Jean-Hugues
    Jean-Hugues ROBERT, Apr 28, 2004
    #18
  19. Re: Semantics of Multiple Values (updated RCR)

    il Wed, 28 Apr 2004 13:35:09 +0900, Jean-Hugues ROBERT
    <> ha scritto::


    >
    >Rather than allowing x, y == 1, 2, I would prefer a more
    >general x, y =~= 1, 2 whose semantic is richer due to the
    >fact that it may end up assigning either x, y or both if
    >they don't exist already (or if they were unbound/freed).
    >


    oh, please no more obscure operators.
    I think little people here would like this route when in the future we
    found ourself using perl6-ish stuff like "@a >>=:=<< @b" :)
    gabriele renzi, Apr 28, 2004
    #19
  20. Kristof Bastiaensen

    Mark Hubbart Guest

    Re: Semantics of Multiple Values (updated RCR)

    On Apr 28, 2004, at 12:14 AM, gabriele renzi wrote:

    > il Wed, 28 Apr 2004 13:35:09 +0900, Jean-Hugues ROBERT
    > <> ha scritto::
    >
    >> Rather than allowing x, y == 1, 2, I would prefer a more
    >> general x, y =~= 1, 2 whose semantic is richer due to the
    >> fact that it may end up assigning either x, y or both if
    >> they don't exist already (or if they were unbound/freed).

    >
    > oh, please no more obscure operators.
    > I think little people here would like this route when in the future we
    > found ourself using perl6-ish stuff like "@a >>=:=<< @b" :)


    Oh, but it would pretty up the language so much!

    |
    $@\\ .-. //@$
    @a >>=:=<< @b
    // -~- \\
    LL ((z)) JJ
    Mark Hubbart, Apr 28, 2004
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?RGltaXRyaXMgUGFudGF6b3BvdWxvcw==?=

    it's all about semantics

    =?Utf-8?B?RGltaXRyaXMgUGFudGF6b3BvdWxvcw==?=, Jul 13, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    327
    =?Utf-8?B?RGltaXRyaXMgUGFudGF6b3BvdWxvcw==?=
    Jul 14, 2004
  2. Schultz
    Replies:
    1
    Views:
    509
    Karl Seguin
    Feb 14, 2005
  3. Luigi Donatello Asero

    Semantics extractor

    Luigi Donatello Asero, Feb 14, 2004, in forum: HTML
    Replies:
    5
    Views:
    545
    Eric Bohlman
    Feb 14, 2004
  4. Alexander Stippler

    destructor / semantics of delete this

    Alexander Stippler, Aug 20, 2003, in forum: C++
    Replies:
    6
    Views:
    2,176
    Chris Theis
    Aug 20, 2003
  5. Patrick
    Replies:
    5
    Views:
    577
    Brian McCauley
    May 3, 2006
Loading...

Share This Page