www.digitalmars.com         C & C++   DMDScript  

D - Other Modern Features

reply "Mark Brudnak" <malibrud provide.net> writes:
I am very new to the D language and have not dug in too deep either.  I am
impressed with what I have seen so far.  Since D is still under developmet,
I would like to know if D has the following features.  If not, then the
plasuability of incorporating them at some point in the future.

1) Multiple return values (like Matlab)

    eg.   (float[] data, string name, string unit) = getChannel(DataFile
file, int chanNo) ;

    This would eliminate alot a repetitive coding.  Also, as an option, the
compiler could force all LHS args to be 'outs' and RHS args to be 'ins'.

2) Variable argument lists for the caller and callee with type information
automatically attached.

    eg.   CALLER:
            delegate myDelegate = func ;
            .
            .
            .
            param[] args ;
            args ~= 1.0 ;
            args ~=  "hello" ;
            myDelegate(args) ;

            CALLEE:
            /* I throw an exception if types do not match */
            func(float a, string message) {
                /* do something */
            }

    eg.    CALLER:
            func2("albert", 1916, "GR") ;

            CALLEE:
            func2( param[] args) {
                switch (args[0].type) {
                    case int:
                    /*etc */
                }
            }

    eg. Use variable argument lists on LHS too.

        CALLER:
        (param[] outArgs) = myDelegate(param[] inArgs) ;

        CALLEE:
        (param[] outArgs) = func(param[] inArgs)  {
            param[] myRetVals ;
            .
            .
            .
            myRetvals ~= result1 ;
            myRetvals ~= result2 ;
            return (myRetVals) ;
        }

3) Native support for plugin modules.  Allow plugin overloading.

    eg. myPict = openPicture("lion.gif") ;
          display(hWind, myPict) ;

        This call is to an abstract proxy class which when called searches
and catalogues all available plugins which have the proper interface.  It
asks each if it can successfully handle the case passed to the abstract
proxy class (eg. can you open a GIF?).  If it can, then it loads the plugin,
instantiates the concrete derived class and returns a reference to it.  All
subsequent calls are handled directly by the plugin.

Thank you,

Mark
Nov 26 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Mark Brudnak" <malibrud provide.net> wrote in message
news:bq3scc$28tl$1 digitaldaemon.com...
 I am very new to the D language and have not dug in too deep either.  I am
 impressed with what I have seen so far.
Thanks! Glad you're here.
  Since D is still under developmet,
 I would like to know if D has the following features.  If not, then the
 plasuability of incorporating them at some point in the future.

 1) Multiple return values (like Matlab)

     eg.   (float[] data, string name, string unit) = getChannel(DataFile
 file, int chanNo) ;

     This would eliminate alot a repetitive coding.  Also, as an option,
the
 compiler could force all LHS args to be 'outs' and RHS args to be 'ins'.
No. But it does have 'out' parameters, which does much the same thing.
 2) Variable argument lists for the caller and callee with type information
 automatically attached.

     eg.   CALLER:
             delegate myDelegate = func ;
             .
             .
             .
             param[] args ;
             args ~= 1.0 ;
             args ~=  "hello" ;
             myDelegate(args) ;

             CALLEE:
             /* I throw an exception if types do not match */
             func(float a, string message) {
                 /* do something */
             }

     eg.    CALLER:
             func2("albert", 1916, "GR") ;

             CALLEE:
             func2( param[] args) {
                 switch (args[0].type) {
                     case int:
                     /*etc */
                 }
             }

     eg. Use variable argument lists on LHS too.

         CALLER:
         (param[] outArgs) = myDelegate(param[] inArgs) ;

         CALLEE:
         (param[] outArgs) = func(param[] inArgs)  {
             param[] myRetVals ;
             .
             .
             .
             myRetvals ~= result1 ;
             myRetvals ~= result2 ;
             return (myRetVals) ;
         }
No. There's been a lot of discussion about this, though.
 3) Native support for plugin modules.  Allow plugin overloading.

     eg. myPict = openPicture("lion.gif") ;
           display(hWind, myPict) ;

         This call is to an abstract proxy class which when called searches
 and catalogues all available plugins which have the proper interface.  It
 asks each if it can successfully handle the case passed to the abstract
 proxy class (eg. can you open a GIF?).  If it can, then it loads the
plugin,
 instantiates the concrete derived class and returns a reference to it.
All
 subsequent calls are handled directly by the plugin.
That seems like it would be a library feature. Would you care to write one?
Nov 28 2003
next sibling parent "Matthew Wilson" <matthew.hat stlsoft.dot.org> writes:
 3) Native support for plugin modules.  Allow plugin overloading.

     eg. myPict = openPicture("lion.gif") ;
           display(hWind, myPict) ;

         This call is to an abstract proxy class which when called
searches
 and catalogues all available plugins which have the proper interface.
It
 asks each if it can successfully handle the case passed to the abstract
 proxy class (eg. can you open a GIF?).  If it can, then it loads the
plugin,
 instantiates the concrete derived class and returns a reference to it.
All
 subsequent calls are handled directly by the plugin.
That seems like it would be a library feature.
Most definitely
Nov 28 2003
prev sibling parent reply "Charles Sanders" <sanders-consulting comcast.net> writes:
 1) Multiple return values (like Matlab)
Boost has accomplished these 'tuples' through some template magic, perhaps the same can be done with D, although i agree I would LOVE to see a language that implemented this. C "Walter" <walter digitalmars.com> wrote in message news:bq8rtf$l6o$1 digitaldaemon.com...
 "Mark Brudnak" <malibrud provide.net> wrote in message
 news:bq3scc$28tl$1 digitaldaemon.com...
 I am very new to the D language and have not dug in too deep either.  I
am
 impressed with what I have seen so far.
Thanks! Glad you're here.
  Since D is still under developmet,
 I would like to know if D has the following features.  If not, then the
 plasuability of incorporating them at some point in the future.

 1) Multiple return values (like Matlab)

     eg.   (float[] data, string name, string unit) = getChannel(DataFile
 file, int chanNo) ;

     This would eliminate alot a repetitive coding.  Also, as an option,
the
 compiler could force all LHS args to be 'outs' and RHS args to be 'ins'.
No. But it does have 'out' parameters, which does much the same thing.
 2) Variable argument lists for the caller and callee with type
information
 automatically attached.

     eg.   CALLER:
             delegate myDelegate = func ;
             .
             .
             .
             param[] args ;
             args ~= 1.0 ;
             args ~=  "hello" ;
             myDelegate(args) ;

             CALLEE:
             /* I throw an exception if types do not match */
             func(float a, string message) {
                 /* do something */
             }

     eg.    CALLER:
             func2("albert", 1916, "GR") ;

             CALLEE:
             func2( param[] args) {
                 switch (args[0].type) {
                     case int:
                     /*etc */
                 }
             }

     eg. Use variable argument lists on LHS too.

         CALLER:
         (param[] outArgs) = myDelegate(param[] inArgs) ;

         CALLEE:
         (param[] outArgs) = func(param[] inArgs)  {
             param[] myRetVals ;
             .
             .
             .
             myRetvals ~= result1 ;
             myRetvals ~= result2 ;
             return (myRetVals) ;
         }
No. There's been a lot of discussion about this, though.
 3) Native support for plugin modules.  Allow plugin overloading.

     eg. myPict = openPicture("lion.gif") ;
           display(hWind, myPict) ;

         This call is to an abstract proxy class which when called
searches
 and catalogues all available plugins which have the proper interface.
It
 asks each if it can successfully handle the case passed to the abstract
 proxy class (eg. can you open a GIF?).  If it can, then it loads the
plugin,
 instantiates the concrete derived class and returns a reference to it.
All
 subsequent calls are handled directly by the plugin.
That seems like it would be a library feature. Would you care to write
one?

Nov 28 2003
next sibling parent reply "Mark Brudnak" <malibrud provide.net> writes:
"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:bq8vs3$qos$1 digitaldaemon.com...
 1) Multiple return values (like Matlab)
Boost has accomplished these 'tuples' through some template magic, perhaps the same can be done with D, although i agree I would LOVE to see a
language
 that implemented this.

 C
is not new and I think that semantically it is cleaner than in, out, inout. For complicated function calls with multiple ins and outs I usually define an in-structure and out-structure to facilitate same thing. This however forces the declaration, allocation and stuffing/unstuffing on the part of the caller and callee (a lot of extra code). For functions which return two or three values, this is overkill. In these cases I have seen functions which return one value, be modified to return two values, one by value, one by reference. i.e. myResult = calculateIt( x, y, z) ; becomes: myResult = calculateIt(x, y, z, t, &anotherResult) ; /* easiest path to add another out */ with multiple return values the code would likely grow as follows myResult = calculateIt( x, y, z) ; becomes: (myResult, anotherResult) = calculateIt(x, y, z, t) ; /* much better ! */
Nov 28 2003
parent reply Berin Loritsch <bloritsch d-haven.org> writes:
Mark Brudnak wrote:
 

 is not new and I think that semantically it is cleaner than in, out, inout.
 For complicated function calls with multiple ins and outs I usually define
 an in-structure and out-structure to facilitate same thing.  This however
 forces the declaration, allocation and stuffing/unstuffing on the part of
 the caller and callee (a lot of extra code).  For functions which return two
 or three values, this is overkill.  In these cases I have seen functions
 which return one value, be modified to return two values, one by value, one
 by reference.
 
 i.e.    myResult = calculateIt( x, y, z) ;
 
 becomes:  myResult = calculateIt(x, y, z, t, &anotherResult) ;  /* easiest
 path to add another out */
 
 with multiple return values the code would likely grow as follows
 
 myResult = calculateIt( x, y, z) ;
 
 becomes:  (myResult, anotherResult)  = calculateIt(x, y, z, t) ;  /* much
 better ! */
Honestly, I have not even thought about a feature like this... Practlically speaking, how would you call such a beast in the client code? (foo, bar) = calculateIt( x, y, z, t ); and if we wanted to explicitly ignore a value: (,bar) = calculateIt( x, y, z, t ); ???
Dec 01 2003
next sibling parent reply "Mark J. Brudnak" <mjbrudna oakland.edu> writes:
"Berin Loritsch" <bloritsch d-haven.org> wrote in message
 Honestly, I have not even thought about a feature like this...
Practlically
 speaking, how would you call such a beast in the client code?

 (foo, bar) = calculateIt( x, y, z, t );

 and if we wanted to explicitly ignore a value:

 (,bar) = calculateIt( x, y, z, t );

 ???
Perhaps, but presumably, you could overload a function based on its return parameter list as well as its argument list. For example class MyClass { int func( int x, int y, int z) { int result ; /* do stuff */ return result ; } (int, float) func( int x, int y, int z) { float bar ; int ibar = func(x, y, z) ; /* do stuff */ return ( ibar, bar ) ; } } Ignoring return parameters may be something necessary however. I would say that they are analogous to default arguments (like C++). Of course it would be difficult to determine which return value one may wish to ignore, so requiring that all ignorable return parameters appear at the end of the parameter list is a bit restrictive. An alternative syntax for ignoring return parameters would be using the null keyword (is 'null' a key word in D?). For example, MyClass me = new MyClass ; int ibar; float bar ; (ibar, null) = me.func(1.0, 2.0, 3.0) ; /* or */ (null, bar) = me.func(1.0, 2.0, 3.0) ; /* or */ (ibar, bar) = me.func(1.0, 2.0, 3.0) ; Another alternative is to use named parameters. (I saw some discussion about this.) For example class MyClass { (int a, float b) func( int x, int y, int z) { float bar ; int ibar ; /* do stuff */ return ( ibar, bar ) ; } } MyClass me = new MyClass ; int ibar; float bar ; (a:ibar) = me.func(1.0, 2.0, 3.0) ; /* or */ (b:bar) = me.func(1.0, 2.0, 3.0) ; /* or */ (a:ibar, b:bar) = me.func(1.0, 2.0, 3.0) ; /* or just */ (ibar, bar) = me.func(1.0, 2.0, 3.0) ; This whole discussion however raises a larger issue. That is, what we are really discussing is expanding and generalizing what an lvalue and rvalue can and should be. For example if an lvalue was allowed to take the form of a parameter list, then the multiple return would be almost free. For example, a parameter list lvalue (and rvalue) would result in statements such as: (x, y) = (r*cos(theta), r*sin(theta)) ; /* which is more compact than.. */ x = r*cos(theta) ; y = r*sin(theta) ; which would function equivalent to the following function call, (x, y) = toCartesian( r, theta) ; /* which is more elegant (IMO) than */ toCartesian( r, theta, &x, &y) ; Mark.
Dec 01 2003
next sibling parent reply Berin Loritsch <bloritsch d-haven.org> writes:
Mark J. Brudnak wrote:

 "Berin Loritsch" <bloritsch d-haven.org> wrote in message
 
Honestly, I have not even thought about a feature like this...
Practlically
speaking, how would you call such a beast in the client code?

(foo, bar) = calculateIt( x, y, z, t );

and if we wanted to explicitly ignore a value:

(,bar) = calculateIt( x, y, z, t );

???
Perhaps, but presumably, you could overload a function based on its return parameter list as well as its argument list. For example class MyClass { int func( int x, int y, int z) { int result ; /* do stuff */ return result ; } (int, float) func( int x, int y, int z) { float bar ; int ibar = func(x, y, z) ; /* do stuff */ return ( ibar, bar ) ; } }
... Runs away screamming ... NOOOOOO!!!!! When the only difference between two functions is the return parameter, you are inviting disaster. How can you guarantee in what context which of the two methods are called? I personally would not want to maintain an application which uses such a construct, and it is explicitly forbidden in other languages. I think for a good reasons. It's a stretch for me just to accept multiple return values--when you throw in differing methods based on return type, things get really messy really fast. Please don't do such a thing.
Dec 01 2003
next sibling parent reply "Mark Brudnak" <malibrud provide.net> writes:
"Berin Loritsch" <bloritsch d-haven.org> wrote

 ... Runs away screamming ... NOOOOOO!!!!!
It is OK, you can run back, please.
 When the only difference between two functions is the return parameter,
you are
 inviting disaster.  How can you guarantee in what context which of the two
 methods are called?
I agree.
 I personally would not want to maintain an application which uses such a
 construct, and it is explicitly forbidden in other languages.  I think for
a
 good reasons.
So do I.
 It's a stretch for me just to accept multiple return values--when you
throw in
 differing methods based on return type, things get really messy really
fast.
 Please don't do such a thing.
Three messages back in the thread you asked about how to ignore a value in the return parameters. The body of my reply enumerates some ideas that I had regarding ignoring return values, one of which was overloading on the return list. I think, if multiple return values were implemented, we should start with the simplest case (fixed return parameter lists) and let the laguage grow from there. The proper direction will not be known until people try the simple case.
Dec 01 2003
parent Berin Loritsch <bloritsch d-haven.org> writes:
Agreed.  However, please don't make it look like an overloaded method that only
differs by return type.  That would be an error IMNSHO.

Mark Brudnak wrote:
 "Berin Loritsch" <bloritsch d-haven.org> wrote
 
 
... Runs away screamming ... NOOOOOO!!!!!
It is OK, you can run back, please.
When the only difference between two functions is the return parameter,
you are
inviting disaster.  How can you guarantee in what context which of the two
methods are called?
I agree.
I personally would not want to maintain an application which uses such a
construct, and it is explicitly forbidden in other languages.  I think for
a
good reasons.
So do I.
It's a stretch for me just to accept multiple return values--when you
throw in
differing methods based on return type, things get really messy really
fast.
Please don't do such a thing.
Three messages back in the thread you asked about how to ignore a value in the return parameters. The body of my reply enumerates some ideas that I had regarding ignoring return values, one of which was overloading on the return list. I think, if multiple return values were implemented, we should start with the simplest case (fixed return parameter lists) and let the laguage grow from there. The proper direction will not be known until people try the simple case.
Dec 02 2003
prev sibling parent Felix <Felix_member pathlink.com> writes:
Some other issues on the multiple params return:

- the values to ignore may be (,,usefulone,,,anotheruseful)=functie(etc1,etc2);
-however, you will not be able anymore to call functie1(functie2(etc1,etc2)) and
this will be a little clumsy:
(v1,v2)=functie2(...);
functie1(v1);

But is something to think more seriously of it




In article <bqfr31$1d2p$1 digitaldaemon.com>, Berin Loritsch says...
Mark J. Brudnak wrote:

 "Berin Loritsch" <bloritsch d-haven.org> wrote in message
 
Honestly, I have not even thought about a feature like this...
Practlically
speaking, how would you call such a beast in the client code?

(foo, bar) = calculateIt( x, y, z, t );

and if we wanted to explicitly ignore a value:

(,bar) = calculateIt( x, y, z, t );

???
Perhaps, but presumably, you could overload a function based on its return parameter list as well as its argument list. For example class MyClass { int func( int x, int y, int z) { int result ; /* do stuff */ return result ; } (int, float) func( int x, int y, int z) { float bar ; int ibar = func(x, y, z) ; /* do stuff */ return ( ibar, bar ) ; } }
... Runs away screamming ... NOOOOOO!!!!! When the only difference between two functions is the return parameter, you are inviting disaster. How can you guarantee in what context which of the two methods are called? I personally would not want to maintain an application which uses such a construct, and it is explicitly forbidden in other languages. I think for a good reasons. It's a stretch for me just to accept multiple return values--when you throw in differing methods based on return type, things get really messy really fast. Please don't do such a thing.
Dec 01 2003
prev sibling parent Felix <Felix_member pathlink.com> writes:
Yeah, maybe the multiple outputs would be a nice feature. However, the issue of
left-side parameters is a little special: they cannot bear an useful information
for the function or they can? Usually when you pass func(&x) you may also give x
an useful value.
But, for programming simplicity, it would be a great enhancement.


In article <bqfq35$1br4$1 digitaldaemon.com>, Mark J. Brudnak says...
"Berin Loritsch" <bloritsch d-haven.org> wrote in message
 Honestly, I have not even thought about a feature like this...
Practlically
 speaking, how would you call such a beast in the client code?

 (foo, bar) = calculateIt( x, y, z, t );

 and if we wanted to explicitly ignore a value:

 (,bar) = calculateIt( x, y, z, t );

 ???
Perhaps, but presumably, you could overload a function based on its return parameter list as well as its argument list. For example class MyClass { int func( int x, int y, int z) { int result ; /* do stuff */ return result ; } (int, float) func( int x, int y, int z) { float bar ; int ibar = func(x, y, z) ; /* do stuff */ return ( ibar, bar ) ; } } Ignoring return parameters may be something necessary however. I would say that they are analogous to default arguments (like C++). Of course it would be difficult to determine which return value one may wish to ignore, so requiring that all ignorable return parameters appear at the end of the parameter list is a bit restrictive. An alternative syntax for ignoring return parameters would be using the null keyword (is 'null' a key word in D?). For example, MyClass me = new MyClass ; int ibar; float bar ; (ibar, null) = me.func(1.0, 2.0, 3.0) ; /* or */ (null, bar) = me.func(1.0, 2.0, 3.0) ; /* or */ (ibar, bar) = me.func(1.0, 2.0, 3.0) ; Another alternative is to use named parameters. (I saw some discussion about this.) For example class MyClass { (int a, float b) func( int x, int y, int z) { float bar ; int ibar ; /* do stuff */ return ( ibar, bar ) ; } } MyClass me = new MyClass ; int ibar; float bar ; (a:ibar) = me.func(1.0, 2.0, 3.0) ; /* or */ (b:bar) = me.func(1.0, 2.0, 3.0) ; /* or */ (a:ibar, b:bar) = me.func(1.0, 2.0, 3.0) ; /* or just */ (ibar, bar) = me.func(1.0, 2.0, 3.0) ; This whole discussion however raises a larger issue. That is, what we are really discussing is expanding and generalizing what an lvalue and rvalue can and should be. For example if an lvalue was allowed to take the form of a parameter list, then the multiple return would be almost free. For example, a parameter list lvalue (and rvalue) would result in statements such as: (x, y) = (r*cos(theta), r*sin(theta)) ; /* which is more compact than.. */ x = r*cos(theta) ; y = r*sin(theta) ; which would function equivalent to the following function call, (x, y) = toCartesian( r, theta) ; /* which is more elegant (IMO) than */ toCartesian( r, theta, &x, &y) ; Mark.
Dec 01 2003
prev sibling parent reply "Mark J. Brudnak" <mjbrudna oakland.edu> writes:
"Berin Loritsch" <bloritsch d-haven.org> wrote >
 Honestly, I have not even thought about a feature like this...
Practlically
 speaking, how would you call such a beast in the client code?

 (foo, bar) = calculateIt( x, y, z, t );

 and if we wanted to explicitly ignore a value:

 (,bar) = calculateIt( x, y, z, t );

 ???
Perhaps you could overload a function based on its return parameter list as well as its argument list. For example class MyClass { int func( int x, int y, int z) { int result ; /* do stuff */ return result ; } (int, float) func( int x, int y, int z) { float bar ; int ibar = func(x, y, z) ; /* do stuff */ return ( ibar, bar ) ; } } Ignoring return parameters may be something necessary however. I would say that they are analogous to default arguments (like C++). Of course it would be difficult to determine which return value one may wish to ignore, so requiring that all ignorable return parameters appear at the end of the parameter list is a bit restrictive. An alternative syntax for ignoring return parameters would be using the null keyword (is 'null' a key word in D?). For example, MyClass me = new MyClass ; int ibar; float bar ; (ibar, null) = me.func(1.0, 2.0, 3.0) ; /* or */ (null, bar) = me.func(1.0, 2.0, 3.0) ; /* or */ (ibar, bar) = me.func(1.0, 2.0, 3.0) ; Another alternative is to use named parameters. (I saw some discussion about this.) For example class MyClass { (int a, float b) func( int x, int y, int z) { float bar ; int ibar ; /* do stuff */ return ( ibar, bar ) ; } } MyClass me = new MyClass ; int ibar; float bar ; (a:ibar) = me.func(1.0, 2.0, 3.0) ; /* or */ (b:bar) = me.func(1.0, 2.0, 3.0) ; /* or */ (a:ibar, b:bar) = me.func(1.0, 2.0, 3.0) ; /* or just */ (ibar, bar) = me.func(1.0, 2.0, 3.0) ; This whole discussion however raises a larger issue. That is, what we are really discussing is expanding and generalizing what an lvalue and rvalue can and should be. For example if an lvalue was allowed to take the form of a parameter list, then the multiple return would be almost free. For example, a parameter list lvalue (and rvalue) would result in statements such as: (x, y) = (r*cos(theta), r*sin(theta)) ; /* which is more compact than.. */ x = r*cos(theta) ; y = r*sin(theta) ; which would function equivalent to the following function call, (x, y) = toCartesian( r, theta) ; /* which is more elegant (IMO) than */ toCartesian( r, theta, &x, &y) ; Mark.
Dec 01 2003
next sibling parent Berin Loritsch <bloritsch d-haven.org> writes:
Mark J. Brudnak wrote:

 "Berin Loritsch" <bloritsch d-haven.org> wrote >
 
Honestly, I have not even thought about a feature like this...
Practlically
speaking, how would you call such a beast in the client code?

(foo, bar) = calculateIt( x, y, z, t );

and if we wanted to explicitly ignore a value:

(,bar) = calculateIt( x, y, z, t );

???
Perhaps you could overload a function based on its return parameter list as well as its argument list. For example class MyClass { int func( int x, int y, int z) { int result ; /* do stuff */ return result ; } (int, float) func( int x, int y, int z) { float bar ; int ibar = func(x, y, z) ; /* do stuff */ return ( ibar, bar ) ; } }
<snip/> NOOO!!! Please see my previous posting on why not. It is a debug nightmare waiting to happen.
Dec 01 2003
prev sibling parent reply "Steve Maillet" <nospam1 EntelechyConsulting.com> writes:
(x, y) = (r*cos(theta), r*sin(theta)) ;
/* which is more compact than.. */
x = r*cos(theta) ;
y = r*sin(theta)  ;
While it may be a few keystrokes more compact it's hardly easier to read or comprehend. Many moons ago I learned programming in APL where the "Butch" programmers did as much as possible in a single line (And in APL it's quite amazing what you can do in a single line of 15-20 characters) However it always ended up as mostly unreadable/unmaintainable. Software changes constantly and language "features" that get in the way of clarity and simnplicity should be avoided as they end up increasing costs of development and decreasing time to market. And that's what makes or breaks projects and companies. (Unless you've been through the rise and fall of a few companies that's not so obvious.) -- Steve Maillet (eMVP) Entelechy Consulting smaillet_AT_EntelechyConsulting_DOT_com
Dec 25 2003
parent reply "Mark Brudnak" <malibrud provide.net> writes:
There are two different issues being discussed in this thread, the first is
multiple return values, the second is the idea of tuples.  The example which
you cite below is an example of the use of tuples.  As such it is used to
highlight the proposed syntax of tuple assignment.  Furthermore, programmers
can write bad code with or without tuples.  The semicolon can be used to
"Butch" code (as you say), e.g.

x = r*cos(theta) ; y = r*sin(theta)  ;

There are may who have opined that the introduction of tuples would enhance
the utility of the language.

It is my belief that high-level languages should allow you to compactly
express your *intentions* in a non-ambiguous way to the compiler.  If there
is a frequently encountered coding pattern which can be reduced and
simplified through the introduction of a new language feature, then the
benefits of such a feature should be carefully considered.

It is not that tuples are in and of them selves are of that much utility
that they should be added to the language, however, by introducing tuples as
a language feature, multiple return values are a natural consequence.  The
best case which I have seen for tuples is the code to swap two variables,
e.g.

(x, y) = (y, x) ;  /* simple, clear, concise */

other useful applications for tupples would be calculations which naturally
linked as such as coordinate conversion

(r, theta) = ( sqrt(x*x + y*y) , atan2(y,x) ) ;

the real power of the tuple comes in multiple return values, e.g.

(r, theta) = toPolar(x, y) ;

...or...

(year, month, day, dayofweek) = getDate() ;

...or...

(hours, min, sec) = getTime() ;

Note that to get the date or time information, phobos returns a string (
toDateString() or toTimeString ) which must be parsed to retrieve the proper
information.  This IMO is a "poor man's" way of doing multiple returns in C.
D should do better.

Thank you,

Mark.

P.S. Merry Christmas.



"Steve Maillet" <nospam1 EntelechyConsulting.com> wrote in message
news:bsg80r$2s5v$1 digitaldaemon.com...
(x, y) = (r*cos(theta), r*sin(theta)) ;
/* which is more compact than.. */
x = r*cos(theta) ;
y = r*sin(theta)  ;
While it may be a few keystrokes more compact it's hardly easier to read
or
 comprehend. Many moons ago I learned programming in APL where the "Butch"
 programmers did as much as possible in a single line (And in APL it's
quite
 amazing what you can do in a single line of 15-20 characters) However it
 always ended up as mostly unreadable/unmaintainable. Software changes
 constantly and language "features" that get in the way of clarity and
 simnplicity should be avoided as they end up increasing costs of
development
 and decreasing time to market. And that's what makes or breaks projects
and
 companies. (Unless you've been through the rise and fall of a few
companies
 that's not so obvious.)

 -- 
 Steve Maillet (eMVP)
 Entelechy Consulting
 smaillet_AT_EntelechyConsulting_DOT_com
Dec 25 2003
parent reply "Steve Maillet" <nospam1 EntelechyConsulting.com> writes:
"(x, y) = (y, x) ;  /* simple, clear, concise */"

That is NOT simple, clear nor concise. But then again neither is the
traditional 3 assignments with a temp variable. In languages with templates
a template library can help with a swap template. However, a built in
swap/exchange statement/operator of some sort as part of the language proper
is a far better answer to a common  pattern such as this.



-- 
Steve Maillet (eMVP)
Entelechy Consulting
smaillet_AT_EntelechyConsulting_DOT_com
Dec 30 2003
parent "Matthew" <matthew.hat stlsoft.dot.org> writes:
"Steve Maillet" <nospam1 EntelechyConsulting.com> wrote in message
news:bst0ks$1m14$1 digitaldaemon.com...
 "(x, y) = (y, x) ;  /* simple, clear, concise */"

 That is NOT simple, clear nor concise. But then again neither is the
 traditional 3 assignments with a temp variable. In languages with
templates
 a template library can help with a swap template. However, a built in
 swap/exchange statement/operator of some sort as part of the language
proper
 is a far better answer to a common  pattern such as this.
I only half-heartedly agree with your analysis, but I do agree that an inbuilt swap would be a very good thing. I'd even go so far as to suggest we have an operator for the purpose. Walter, shoot me down with your compiler-waltering lore, but how about x <> y or x >< y or x >=< y ? :) Dr Proctor
Dec 30 2003
prev sibling parent reply "Matthew Wilson" <matthew.hat stlsoft.dot.org> writes:
"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:bq8vs3$qos$1 digitaldaemon.com...
 1) Multiple return values (like Matlab)
Boost has accomplished these 'tuples' through some template magic, perhaps the same can be done with D, although i agree I would LOVE to see a
language
 that implemented this.
I'd rather see it in the language, but if it's not I've no doubt it'll find its way in when the templates get a serious shake.
Nov 28 2003
next sibling parent Ilya Minkov <minkov cs.tum.edu> writes:
Matthew Wilson wrote:
 I'd rather see it in the language, but if it's not I've no doubt it'll find
 its way in when the templates get a serious shake.
With explicit intantiation we're probably back at custom return structs... So better allow for simple type inference (Sather's ::= operator) and anonymous structs. Call them tuples then if you like. -eye
Nov 29 2003
prev sibling parent reply Felix <Felix_member pathlink.com> writes:
Just a thought: I work in Matlab so I use the multiple return parameters.
However, there are a few issues:

-concerning the "C"/"D" return values (i.e. using "return x;" would have to be
chnaged too, to accept multiple parameters). else, using a more "Pascal"-like
approach, i.e. returning the output parameters with the last value they have
before quiting the fcn. will simply change some fondamental concepts.
-in Matlab, one feature missing is the non-reference parameters transfer. This
means that, for each function affecting x you must write x=domsmthngto(x). IMO,
this should be avoided in "D". Is not very cool.


Felix




In article <bq9e98$1f9f$1 digitaldaemon.com>, Matthew Wilson says...
"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:bq8vs3$qos$1 digitaldaemon.com...
 1) Multiple return values (like Matlab)
Boost has accomplished these 'tuples' through some template magic, perhaps the same can be done with D, although i agree I would LOVE to see a
language
 that implemented this.
I'd rather see it in the language, but if it's not I've no doubt it'll find its way in when the templates get a serious shake.
Dec 01 2003
parent reply "Mark J. Brudnak" <mjbrudna oakland.edu> writes:
The syntax should be:

(int, float, double) funct( char[] foo, int bar) {
    int result1 ;
    float result2;
    double result3 ;

    /* do stuff */

    return (result1, result2, result3) ;
}

This would ofcourse impose a special meaning on the parenthesis and comma
for the return statement.  I assume that D did away with the C-"comma
operator" so there would be no ambiguity in the syntax.  This amounts to
nothing more than a compiler generated struct used only for the passing of
parameters on return.

mark.


"Felix" <Felix_member pathlink.com> wrote in message
news:bqesvv$310k$1 digitaldaemon.com...
 Just a thought: I work in Matlab so I use the multiple return parameters.
 However, there are a few issues:

 -concerning the "C"/"D" return values (i.e. using "return x;" would have
to be
 chnaged too, to accept multiple parameters). else, using a more
"Pascal"-like
 approach, i.e. returning the output parameters with the last value they
have
 before quiting the fcn. will simply change some fondamental concepts.
 -in Matlab, one feature missing is the non-reference parameters transfer.
This
 means that, for each function affecting x you must write x=domsmthngto(x).
IMO,
 this should be avoided in "D". Is not very cool.


 Felix




 In article <bq9e98$1f9f$1 digitaldaemon.com>, Matthew Wilson says...
"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:bq8vs3$qos$1 digitaldaemon.com...
 1) Multiple return values (like Matlab)
Boost has accomplished these 'tuples' through some template magic,
perhaps
 the same can be done with D, although i agree I would LOVE to see a
language
 that implemented this.
I'd rather see it in the language, but if it's not I've no doubt it'll
find
its way in when the templates get a serious shake.
Dec 01 2003
parent reply Makaan Kublai Kahn <Makaan_member pathlink.com> writes:
In article <bqffkg$qin$1 digitaldaemon.com>, Mark J. Brudnak says...
The syntax should be:

(int, float, double) funct( char[] foo, int bar) {
    int result1 ;
    float result2;
    double result3 ;

    /* do stuff */

    return (result1, result2, result3) ;
}

This would ofcourse impose a special meaning on the parenthesis and comma
for the return statement.  I assume that D did away with the C-"comma
operator" so there would be no ambiguity in the syntax.  This amounts to
nothing more than a compiler generated struct used only for the passing of
parameters on return.

mark.


"Felix" <Felix_member pathlink.com> wrote in message
news:bqesvv$310k$1 digitaldaemon.com...
 Just a thought: I work in Matlab so I use the multiple return parameters.
 However, there are a few issues:

 -concerning the "C"/"D" return values (i.e. using "return x;" would have
to be
 chnaged too, to accept multiple parameters). else, using a more
"Pascal"-like
 approach, i.e. returning the output parameters with the last value they
have
 before quiting the fcn. will simply change some fondamental concepts.
 -in Matlab, one feature missing is the non-reference parameters transfer.
This
 means that, for each function affecting x you must write x=domsmthngto(x).
IMO,
 this should be avoided in "D". Is not very cool.


 Felix




 In article <bq9e98$1f9f$1 digitaldaemon.com>, Matthew Wilson says...
"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:bq8vs3$qos$1 digitaldaemon.com...
 1) Multiple return values (like Matlab)
Boost has accomplished these 'tuples' through some template magic,
perhaps
 the same can be done with D, although i agree I would LOVE to see a
language
 that implemented this.
I'd rather see it in the language, but if it's not I've no doubt it'll
find
its way in when the templates get a serious shake.
You can already do this. You can return a struct I in C and C++. A struct can contain more than one value and encapsulate more than one return of types. It is better to return a struct of values than have a multiple return for functions. This is how it was intended to return multiple types. A link for gcc is: http://gcc.gnu.org/ml/gcc/1998-11/msg01087.html Here's an example from that link of returning a struct: ================================================================== -- z1.c -------------------------------------------------------- struct s { int x; }; struct s func (int y) { struct s xx; xx.x = y * 10; return xx; } -- z2.c -------------------------------------------------------- struct s { int x; }; extern struct s func (int y); void func2 (struct s x1, struct s x2) { printf ("%d %d\n", x1.x, x2.x); } int main () { func2 (func (1), func (2)); } ---------------------------------------------------------------- On linux, compile z1.c with gcc 2.7.2 and z2.c with egcs and link them together. The resulting program prints 10 1 rather than the expected 10 20 ==========================================================
Dec 01 2003
parent reply "Mark J. Brudnak" <mjbrudna oakland.edu> writes:
"Makaan Kublai Kahn" <Makaan_member pathlink.com> wrote

 You can already do this.  You can return a struct I in C and C++.
 A struct can contain more than one value and encapsulate more than one
return
 of types.  It is better to return a struct of values than have a multiple
return
 for functions.  This is how it was intended to return multiple types.
Yes, but why should you have to define a structure just because you have to return two or three values rather than one? It is more code to write. The compiler knows all of the relevent information to define the structure implicitly. In other words the compiler is responsible for generating the struct. For example. FOR THE CALLER SIDE =================== D code as written: int x ; float y ; (x, y) = func(10, 3.14159, "foo") ; The compiler then compiles it as if I had written: int x ; float y ; { /* compiler generated block statement */ struct tempStruct { int var1 ; float var2 ; } tempStruct temp ; temp = func(10, 3.14159, "foo") ; x = temp.var1 ; y = temp.var2 ; } FOR THE CALLEE SIDE =================== D code as written: (int , float) = func(int a, float b, char [] c) { int result1 ; float result2 ; /* do stuff */ return( result1, result2 ) ; } The compiler then compiles it as if I had written: (int , float) = func(int a, float b, char [] c) { int result1 ; float result2 ; /* do stuff */ { /* compiler generated block statement */ struct tempStruct { int var1 ; float var2 ; } tempStruct temp ; temp.var1 = result1 ; temp.var2 = result2 ; return temp ; }/* end compiler generated block statement */ } This is also what happens to the aruments as well. They are stuffed into an implicitly defined structure consisting of either the registers and/or the stack in a well defined way. It is only natural to do the same thing in reverse. (i.e. use the registers and stack to pass back multiple return values in a well defined way. In this case our ficticious compiler used a struct, in an actual implementation it would use some registers and then the stack.) mark.
 A link for gcc is:  http://gcc.gnu.org/ml/gcc/1998-11/msg01087.html

 Here's an example from that link of returning a struct:

 ==================================================================
 -- z1.c --------------------------------------------------------

 struct s {
 int x;
 };

 struct s func (int y)
 {
 struct s xx;
 xx.x = y * 10;
 return xx;
 }

 -- z2.c --------------------------------------------------------

 struct s {
 int x;
 };

 extern struct s func (int y);

 void func2 (struct s x1, struct s x2)
 {
 printf ("%d %d\n", x1.x, x2.x);
 }


 int main ()
 {
 func2 (func (1), func (2));
 }
 ----------------------------------------------------------------


 On linux, compile z1.c with gcc 2.7.2 and z2.c with egcs and link
 them together.  The resulting program prints

 10 1

 rather than the expected

 10 20

 ==========================================================
Dec 01 2003
next sibling parent reply Georg Wrede <Georg_member pathlink.com> writes:
In article <bqgbtf$2726$1 digitaldaemon.com>, Mark J. Brudnak says...
"Makaan Kublai Kahn" <Makaan_member pathlink.com> wrote
 You can already do this.  You can return a struct I in C and C++.
 A struct can contain more than one value and encapsulate more than 
 one return of types.  It is better to return a struct of values 
 than have a multiple return for functions.  This is how it was
 intended to return multiple types.
Functions returning several values could be used like (a,b,c) = func(d,e,f,g); Using this we could make the code clearer and easier to understand if we decided that (d,e,f,g) could only be in-parameters, and that the only way to get out- functionality is via return values (e.g. (a,b,c)). This would make the code quite readable. But the cost, and the pre-requisite, would be to skip out-parameters entirely from the language. Why? Well, if we are browsing code written by others, then we either can rely on the right side being input- only, or then we can't. Only if we can do that, the code becomes readily browsable for us. This brings up the question, should we do this? I for one would think that this is a truly interesting aspect, and it may contain quite some promises. OTOH, this would be such a profound change in the language that we may risk alienating C(++), Java, and other users. So, this had better be worth the cost. Also, if we went for this kind of strategy, then why not make both the in- (the right side) and the out- (the left side) streamable! That is, a function could take any number of parameters, and it could also return an arbitrary number of parameters! Well, such languages exist already. APL I think is one. But from what I've had to program with APL, this sure doesn't contribute to the overall readability when it comes right down to it. Then there is another solution. A company using D could internally decide that every function takes one in-parameter and one out-parameter. They would be structs. This would of course lead to assignments both at the input and the output, but since Good Code has short functions, most of the locals could be in structs to begin with. Standardising these structs could result in increased clarity and maybe even more overall structure in the program. And we could skip a profound remake of D.
Dec 01 2003
next sibling parent reply "Ben Hinkle" <bhinkle4 juno.com> writes:
 Also, if we went for this kind of strategy, then why
 not make both the in- (the right side) and the out-
 (the left side) streamable! That is, a function
 could take any number of parameters, and it could
 also return an arbitrary number of parameters!
 Well, such languages exist already. APL I think
 is one. But from what I've had to program with
 APL, this sure doesn't contribute to the overall
 readability when it comes right down to it.
MATLAB allows both a variable number of inputs and outputs. It does this by reserving the parameter names "varargin" and "varargout" to have special meaning (they collect all the remaining inputs or outputs into a list). It also defines the variables "nargin" and "nargout" in the function body to be the number of inputs and outputs. Multiple outputs are used very often in MATLAB code. varargout is used much less frequently, and most uses probably are to implement generic function evaluators. -Ben
Dec 01 2003
next sibling parent reply "Mark Brudnak" <malibrud provide.net> writes:
"Ben Hinkle" <bhinkle4 juno.com> wrote

 MATLAB allows both a variable number of inputs and outputs. It does this
by
 reserving the parameter names "varargin" and "varargout" to have special
 meaning (they collect all the remaining inputs or outputs into a list). It
 also defines the variables "nargin" and "nargout" in the function body to
be
 the number of inputs and outputs.
 Multiple outputs are used very often in MATLAB code. varargout is used
much
 less frequently, and most uses probably are to implement generic function
 evaluators.

 -Ben
Yes, but Matlab != D Matlab is interpreted and is therefore slow. Don't get me wrong, I love Matlab, but when speed is necessary, a compiled, optimized language is necesary. For me, I like C, I avoid C++ and D is appealing. Since D is still being developed, multiple returns seem like a nice addition. Mark.
Dec 01 2003
parent reply brad beveridge <brad nospam.com> writes:
How would multiple returns work if you don't provide places for the 
returns to go?
ie
(int, int) = someFunc(int);

(a) = someFunc(10);

Further to that, how would nested functions work?
(int) = someFunc(int, int, int)
(int, int, int) = foo(float)

(a) = someFunc(foo(10.0));

What about determining which function to call based on the return type?
(int) = foo(int)
(int, int) = foo(int)

(a,b) = foo(10);
c = foo(5);

I don't know how complex that is starting to get for the compiler.  I 
like the idea of mulitple returns, it can be very handy - but I get the 
feeling that it is probably quite hard to implement in a compiler.

Brad

 "Ben Hinkle" <bhinkle4 juno.com> wrote
 
 
MATLAB allows both a variable number of inputs and outputs. It does this
by
reserving the parameter names "varargin" and "varargout" to have special
meaning (they collect all the remaining inputs or outputs into a list). It
also defines the variables "nargin" and "nargout" in the function body to
be
the number of inputs and outputs.
Multiple outputs are used very often in MATLAB code. varargout is used
much
less frequently, and most uses probably are to implement generic function
evaluators.

-Ben
Yes, but Matlab != D Matlab is interpreted and is therefore slow. Don't get me wrong, I love Matlab, but when speed is necessary, a compiled, optimized language is necesary. For me, I like C, I avoid C++ and D is appealing. Since D is still being developed, multiple returns seem like a nice addition. Mark.
Dec 01 2003
next sibling parent "Mark Brudnak" <malibrud provide.net> writes:
"brad beveridge" <brad nospam.com> wrote in message
news:bqguk7$31jb$1 digitaldaemon.com...
 How would multiple returns work if you don't provide places for the
 returns to go?
 ie
 (int, int) = someFunc(int);
A call would look like this. type1 foo ; type2 bar ; (foo, bar) = someFunc(param1, param2, /* etc*/) ;
 (a) = someFunc(10);

 Further to that, how would nested functions work?
 (int) = someFunc(int, int, int)
 (int, int, int) = foo(float)

 (a) = someFunc(foo(10.0));
Nesting for the time being should not be allowed. The function should return a parameterized rvalue ready for assignment to a suitable lvalue. If a compelling case arises this could be explored.
 What about determining which function to call based on the return type?
 (int) = foo(int)
 (int, int) = foo(int)

 (a,b) = foo(10);
 c = foo(5);
Probably not a good place to start.
 I don't know how complex that is starting to get for the compiler.  I
 like the idea of mulitple returns, it can be very handy - but I get the
 feeling that it is probably quite hard to implement in a compiler.

 Brad

 "Ben Hinkle" <bhinkle4 juno.com> wrote


MATLAB allows both a variable number of inputs and outputs. It does this
by
reserving the parameter names "varargin" and "varargout" to have special
meaning (they collect all the remaining inputs or outputs into a list).
It
also defines the variables "nargin" and "nargout" in the function body
to
 be

the number of inputs and outputs.
Multiple outputs are used very often in MATLAB code. varargout is used
much
less frequently, and most uses probably are to implement generic
function
evaluators.

-Ben
Yes, but Matlab != D Matlab is interpreted and is therefore slow. Don't get me wrong, I love Matlab, but when speed is necessary, a compiled, optimized language is necesary. For me, I like C, I avoid C++ and D is appealing. Since D is still being developed, multiple returns seem like a nice addition. Mark.
Dec 01 2003
prev sibling parent Sarat Venugopal <sarat removeme.huelix.com> writes:
Hello Brad,

 How would multiple returns work if you don't provide places for the 
 returns to go?
 ie
 (int, int) = someFunc(int);
 
 (a) = someFunc(10);
Two possibilities: 1) Compiler error - all parameters are mandatory 2) When there are fewer LHS variables, they are assigned starting from the first one, if types match. Harder for everyone, though.
 Further to that, how would nested functions work?
 (int) = someFunc(int, int, int)
 (int, int, int) = foo(float)
 
 (a) = someFunc(foo(10.0));
One useful feature of tuples in Python is automatic packing and unpacking. (int, float) Func(); // Or just "int, float Func()"? and call it as: int i; float f; i, f = Func(); With the compiler automatically managing the packing into a tuple. Your "nested functions" (I would think they are an entirely different beast!) could benefit from automatic unpacking as well. (a) = someFunc(foo(10.0)); This would translate into a = someFunc(a, b, c); where a,b,c forms the tuple (a, b, c) returned by foo().
 What about determining which function to call based on the return type?
 (int) = foo(int)
 (int, int) = foo(int)
 
 (a,b) = foo(10);
 c = foo(5);
In this case there is no ambiguity. In fact, these are unrelated issues - returning multiple values and overloading on return types. Actually if you have the former, there is less incentive to have the latter. The whole issue of overloading by return type is probably centered around the fact that in most languages one can ignore the return type. I am told Ada supports overloading on return types and return values can never be ignored. Anyone with good Ada experience would like to comment?
 I don't know how complex that is starting to get for the compiler.  I 
 like the idea of mulitple returns, it can be very handy - but I get the 
 feeling that it is probably quite hard to implement in a compiler.
I remember seeing a discussion on the web (couple of years back?) by the designers of C, C++ and Java. Asked what they would change if they were to do it all over again, James Gosling cited multiple return values as a major one (Ha, I found an archived link - http://www.gotw.ca/publications/c_family_interview.htm). Of course, I am not advocating anything here. Multiple return values is one feature, I think, that can't be added as an afterthought. I mean, in a seamless manner. I think that may be the reason Java still doesn't have it. All of the things discussed in this thread exist in various other languages. But of course, that's not enough of a reason to put them all into D. Cheers, Sarat Venugopal
Dec 02 2003
prev sibling parent reply "Steve Maillet" <nospam1 EntelechyConsulting.com> writes:
What's good for MATLAB is not necessarily good for D. These are two VERY
different languages with different problem domains, and users. I've lived
through some REALLY long debug sessions where someone used a language
feature to save a couple of bytes of source code space instead of making it
clear and simple to understand.

A struct or class makes more sense as the returned values are all related
together in some way or they wouldn't be returned from the same function.

-- 
Steve Maillet (eMVP)
Entelechy Consulting
smaillet_AT_EntelechyConsulting_DOT_com
Dec 25 2003
next sibling parent "Mark Brudnak" <malibrud provide.net> writes:
"Steve Maillet" <nospam1 EntelechyConsulting.com> wrote in message
news:bsg8f3$2t06$1 digitaldaemon.com...
 What's good for MATLAB is not necessarily good for D. These are two VERY
 different languages with different problem domains, and users.
Agreed!
 I've lived
 through some REALLY long debug sessions where someone used a language
 feature to save a couple of bytes of source code space instead of making
it
 clear and simple to understand.
Some language features can be used with great power by some and abused to great extremes by others. This says more about the programmer than it does about the feature. (it is unfortunate that there are many books which encourage the abuse of language features, especially C books.)
 A struct or class makes more sense as the returned values are all related
 together in some way or they wouldn't be returned from the same function.
Not true. If a structure's only purpose is to return multiple values, then IMO it complicates an interface rather than simplifies it because a temporary instance must be created to shuffle out of the function.
 -- 
 Steve Maillet (eMVP)
 Entelechy Consulting
 smaillet_AT_EntelechyConsulting_DOT_com
Finally, I think that the reason that functions only return one value has more to do with mathematics than with computer science. The name is borrowed from the familiar mathematical concept we all learned in Algebra, Trig, Calc, for example, log(x), tan(y), sin(z), etc. The reality is that most of the mathematical functions which are handled in these courses are "single valued" meaning that they map to the real numbers. Occasionally we studied functions which take complex values. Similarly on the parameter side, we often encounter single parameters in our math classes. For some reason, when the computer scientists borrowed the concept, they extended and generalized the parameters to be multiple valued, but, in general, did not extend the return values in the same way. The reason for this IMO (this is pure speculation) is that in math class we were all taught that "functions are single valued" meaning that each point in the domain must map to *only one* point in the range. Mathematical functions, however, are defined as a mapping from the domain to the range where each element in the range may very well be an aggregate of simpler objects, or multiple valued. Having said this, I think multiple return vales would be logical generalization of the borrowed concept of a function just as multiple parameters were. Mark.
Dec 25 2003
prev sibling parent reply davepermen <davepermen_member pathlink.com> writes:
A struct or class makes more sense as the returned values are all related
together in some way or they wouldn't be returned from the same function.
so all of your functions only have one parameter as well? because this makes more sence then as well. and if multiple parameters are needed, you pass them as struct, right?
Dec 26 2003
parent reply "Steve Maillet" <nospam1 EntelechyConsulting.com> writes:
You are comparing apples to oranges the mathematical definition of a
function allows for multiple inputs and a single output. (Note: that output
can be a complex number, a vector or matrix, etc...) The idea of multiple
return types goes against that. It also makes for some very ugly and
difficult to debug code. I've been there and done that and most of the time
there is no need for it and the few times that it is required struts work
just fine and are easy enough to code. Should the language have a means to
automatically  and efficiently handle the return of a strict so there isn't
a copy involve - sure. But that's a compiler implementation detail not a
language definition one.

-- 
Steve Maillet (eMVP)
Entelechy Consulting
smaillet_AT_EntelechyConsulting_DOT_com
Dec 30 2003
parent reply qw <qw_member pathlink.com> writes:
In article <bst09c$1le5$1 digitaldaemon.com>, Steve Maillet says...
You are comparing apples to oranges the mathematical definition of a
function allows for multiple inputs and a single output. (Note: that output
can be a complex number, a vector or matrix, etc...) The idea of multiple
return types goes against that. It also makes for some very ugly and
difficult to debug code.
Why would x, y = func(a, b) be any harder to debug than func(a, b, &x, &y) ??? To me, the 1st form is better because you see what are the inputs and outputs. In the second form, you could be passing pointers for efficiency, to for "out" parameters. Worse, in C++, the 2nd form could be: func(a, b, x, y) // declaration: void func(T a, T b, T& x, T& y) It's much harder to tell what are the inputs and what are the outputs... You could think of multiple return as returning a composite object (tuple) and decomposing it at the assignment. So, it doesn't go against your beloved math. (i don't think programming is math, but...)
Dec 30 2003
next sibling parent reply "Steve Maillet" <nospam1 EntelechyConsulting.com> writes:
Why would
 x, y = func(a, b)
 be any harder to debug than
func(a, b, &x, &y)
It wouldn't - both versions of the syntax, quite frankly, suck. instead it should be: Point pos = func(a,b); or perhaps Point input; Point Output; Output = func(Input); depending on exactly what it is that func is doing. -- Steve Maillet (eMVP) Entelechy Consulting smaillet_AT_EntelechyConsulting_DOT_com
Dec 31 2003
parent Lewis <dethbomb hotmail.com> writes:
Steve Maillet wrote:
Why would
x, y = func(a, b)
be any harder to debug than
func(a, b, &x, &y)
It wouldn't - both versions of the syntax, quite frankly, suck. instead it should be: Point pos = func(a,b); or perhaps Point input; Point Output; Output = func(Input); depending on exactly what it is that func is doing.
that would be very nice, as thats whats im used to also. You should definetly be able to return a struct (if you cant) and a value from an non-anonymous enum, and a object. in vb we can do something like this Listview lv = new Listview; //this dynamicly adds an item, returns a reference and you can inline add text to the subitem lv.ListItems.Add("test","test").SubItems(1).Text = "test"; //or struct Foo { int A; int B; } Foo InitStruct(int a,int b) { Foo c; c.A = a; c.B = b; return c; } //which i think you can already do, but even better would be Foo InitStruct(int a,int b) { InitStruct.A = a; InitStruct.B = b; return; }
Dec 31 2003
prev sibling parent reply "Steve Maillet" <nospam1 EntelechyConsulting.com> writes:
"You could think of multiple return as returning a composite object (tuple)"

Yes, you could and IMHO you SHOULD. The beauty of that is that __EXISTING__
language constructs allow you to do so already! Templates/generics allow you
to create typesafe Tuple templates for any kind of paired return type; in
fact STL already has the Pair template for C++ programmers to do just that.
This is far more flexible and allows for compile time type checking without
inventing or adding new concepts into the language. As I, and others, have
mentioned the syntax of returning a struct or class is a bit clumsy in most
"C" derivative languages and there is room to improve that in a new and
emerging language such as "D". However, adding a completely new concept that
is adequately supported with other existing constructs is a bad idea.
(Especially when the only reason for not using a struct/class as a return
type that has been offered thus far is the "clumsy" syntax of creating a
temp in the actual method implementation. [Remember that even in the beloved
multiple return values the compiler will have to do that underneath anyway.)
So, I say lets' focus on ideas to improve that syntax without breaking the
familiarity with C or compromising efficiency.

By way of some examples VB and Pascal use the function name as an implicit
local for the return value so we could make a function like this:

Point Foo(float r, float theta)
{
    Foo.x = r*cos(theta) ;
    Foo.y = r*sin(theta) ;
}

The compiler is able to optimize that to the actual return type and
eliminate any copy on return in many cases.  However, the existing return
statement should be supported as well. This resolves the syntactical issues
and provides for highly flexible tuples and other multiple return types
using __EXISTING__ typesafe language constructs with minimal effort on the
compiler creators and no further imposition on the programmer.

Furthermore, using the above syntax and structs allows for assignment of the
members in any particular order without the need to create or store temps.
Consider how the code would have to look if the resulting return type were
implemented as proposed (e.g. "(x, y) = (r*cos(theta), r*sin(theta)) ") The
language would HAVE to specifiy an order of execution for the sub
expressions of the rvalue. And in the case where the actual functions needed
to operate in a different order things get ugly with temps really fast.
However, using structures or objects (with a minor syntactical cleanup) as
shown above the issue simply doesn't exist.

-- 
Steve Maillet (eMVP)
Entelechy Consulting
smaillet_AT_EntelechyConsulting_DOT_com
Dec 31 2003
next sibling parent Ilya Minkov <minkov cs.tum.edu> writes:
Steve Maillet wrote:
 fact STL already has the Pair template for C++ programmers to do just that.
Yup. and there are tuples in boost. The problem is, D templates lack of implicit instantiation, which makes them much less appropriate for this kind of stuff. However, Walter promised some changes in templates. I wonder what those would be. I would prefer for templates to stay as they are, bacause they are great for many things and are nontheless simple to implement correctly. Also, they already open up another world on efficiency. In C++, templates are used to patch up the otherwise minimalistic language. That was not the original idea of D. That's why we have sliced and associative arrays directly in the langiage. And thus i would prefer that tuples (anonymous structs) also make it into the language. -eye
Jan 01 2004
prev sibling parent "Mark Brudnak" <malibrud provide.net> writes:
"Steve Maillet" <nospam1 EntelechyConsulting.com> wrote in message
news:bsurmr$19dt$1 digitaldaemon.com...
 "You could think of multiple return as returning a composite object
(tuple)"
 Yes, you could and IMHO you SHOULD. The beauty of that is that
__EXISTING__
 language constructs allow you to do so already! Templates/generics allow
you
 to create typesafe Tuple templates for any kind of paired return type; in
 fact STL already has the Pair template for C++ programmers to do just
that. Defining a struct for the sole purpose of returning multiple values is the simplest way, defining a template to do this is just down right cumbersome and unnecessary.
 This is far more flexible and allows for compile time type checking
without
 inventing or adding new concepts into the language.
Tuples can be compile time checked, but at the element level. In the truest sense there is no type associated with a tuple. It is a collection of types which is implicitly defined by the types it contains. These types must match across an assignment.
 As I, and others, have
 mentioned the syntax of returning a struct or class is a bit clumsy in
most
 "C" derivative languages and there is room to improve that in a new and
 emerging language such as "D". However, adding a completely new concept
that
 is adequately supported with other existing constructs is a bad idea.
Multiple returns and tuples are not new concepts. Taking your point to the extremes, most of the features of D are not necessary. They are there because they make frequently encountered patterns easier. Why was array slicing introduced in D? Because it makes frequent tasks easier to code. They do not add new ability to manipulate arrays, they just make it easier.
 (Especially when the only reason for not using a struct/class as a return
 type that has been offered thus far is the "clumsy" syntax of creating a
 temp in the actual method implementation. [Remember that even in the
beloved
 multiple return values the compiler will have to do that underneath
anyway.) IMO the more the compiler does "underneath" the better. That is the point of high-level programming languages.
 So, I say lets' focus on ideas to improve that syntax without breaking the
 familiarity with C or compromising efficiency.
D has broken with C/C++ in several areas, introducing new constructs where needed. C is 30+ years old, C++ is 20+ years old. New ideas have been introduced in newer languages. I would be foolish to reject new constructs just to stay with C/C++ syntax.
 By way of some examples VB and Pascal use the function name as an implicit
 local for the return value so we could make a function like this:

 Point Foo(float r, float theta)
 {
     Foo.x = r*cos(theta) ;
     Foo.y = r*sin(theta) ;
 }

 The compiler is able to optimize that to the actual return type and
 eliminate any copy on return in many cases.  However, the existing return
 statement should be supported as well. This resolves the syntactical
issues
 and provides for highly flexible tuples and other multiple return types
 using __EXISTING__ typesafe language constructs with minimal effort on the
 compiler creators and no further imposition on the programmer.

 Furthermore, using the above syntax and structs allows for assignment of
the
 members in any particular order without the need to create or store temps.
 Consider how the code would have to look if the resulting return type were
 implemented as proposed (e.g. "(x, y) = (r*cos(theta), r*sin(theta)) ")
OK. --- callee side --- (float, float) Foo(float r, float theta) { return ( r*cos(theta), r*sin(theta) ) ; } --- caller side --- (x, y) = Foo(r, theta) ;
 The
 language would HAVE to specifiy an order of execution for the sub
 expressions of the rvalue.
The D spec says that the order of execution within a statement is reserved for the compiler to determine. Tuples would be the same way.
 And in the case where the actual functions needed
 to operate in a different order things get ugly with temps really fast.
 However, using structures or objects (with a minor syntactical cleanup) as
 shown above the issue simply doesn't exist.
In your way of thinking, you should always use a temporary structure to pass multiple parameters as well. What is the difference between a = func(b, c, d) ; ...and ... (e, f, g) = func(h) ; In your argument both cases are unnecessary and should be coded as. struct Foo { type1 a ; type2 b ; type3 c ; } Foo foo ; foo.a = 1 ; foo.b = 2 ; foo.c = 3 ; a = func(foo) ; ...and ... struct Foo { type1 e ; type2 f ; type3 g ; } Foo foo = func(h) ; ; type1 e = foo.e ; type2 f = foo.f ; type3 g = foo.g ; I do not see the efficiency in this. Mark.
 -- 
 Steve Maillet (eMVP)
 Entelechy Consulting
 smaillet_AT_EntelechyConsulting_DOT_com
Jan 01 2004
prev sibling parent reply "Mark Brudnak" <malibrud provide.net> writes:
We should crawl before we walk or run.  I think a nice start would be to
implement multiple return values.

(a, b, c) = foo(p1, p2, p3) ;

1) Rules for passing parameters remain the same.

2) Functions may not be over loaded via their return parameter lists.

3) Define parameterized lvalues and rvalues.

    i.e. (a, b, c) = (e+f, z*u, n*m) ; /* valid statement */
    i.e. (x, y) = (r*cos(theta), r*sin(theta)) ; /* valid statement */
    i.e. (x, y) = toCartesian( r, theta) ;    /* toCartesian returns a
parmeterized rvalue */

4) Multiple return values are passed back via registers and stack in a
well-defined way.

5) Single output functions use the current calling conventions.

6) Multiple return value functions cannot be linked by another language.
The call is D to D.

Mark.

"Georg Wrede" <Georg_member pathlink.com> wrote

 Functions returning several values could be used like

 (a,b,c) = func(d,e,f,g);

 Using this we could make the code clearer and easier
 to understand if we decided that (d,e,f,g) could only
 be in-parameters, and that the only way to get out-
 functionality is via return values (e.g. (a,b,c)).
Nice, but not necessary.
 This would make the code quite readable. But the cost,
 and the pre-requisite, would be to skip out-parameters
 entirely from the language.
Not necessary. This would certainly break existing code and also break C backward compatability (I think).
 Why? Well, if we are browsing code written by others,
 then we either can rely on the right side being input-
 only, or then we can't. Only if we can do that, the
 code becomes readily browsable for us.

 This brings up the question, should we do this?

 I for one would think that this is a truly interesting
 aspect, and it may contain quite some promises. OTOH,
 this would be such a profound change in the language
 that we may risk alienating C(++), Java, and other
 users. So, this had better be worth the cost.
I do not think this would be a profound change.
 Also, if we went for this kind of strategy, then why
 not make both the in- (the right side) and the out-
 (the left side) streamable! That is, a function
 could take any number of parameters, and it could
 also return an arbitrary number of parameters!
 Well, such languages exist already. APL I think
 is one. But from what I've had to program with
 APL, this sure doesn't contribute to the overall
 readability when it comes right down to it.
This would a lot all at once.
 Then there is another solution. A company using D
 could internally decide that every function takes
 one in-parameter and one out-parameter. They would
 be structs. This would of course lead to assignments
 both at the input and the output, but since Good
 Code has short functions, most of the locals could
 be in structs to begin with. Standardising these
 structs could result in increased clarity and maybe
 even more overall structure in the program.

 And we could skip a profound remake of D.

Dec 01 2003
parent reply Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari gamma.hut.fi> writes:
In article <bqgvbc$14a$1 digitaldaemon.com>, Mark Brudnak wrote:
 We should crawl before we walk or run.  I think a nice start would be to
 implement multiple return values.
 
 (a, b, c) = foo(p1, p2, p3) ;
 
 1) Rules for passing parameters remain the same.
 
 3) Define parameterized lvalues and rvalues.
 
     i.e. (a, b, c) = (e+f, z*u, n*m) ; /* valid statement */
     i.e. (x, y) = (r*cos(theta), r*sin(theta)) ; /* valid statement */
     i.e. (x, y) = toCartesian( r, theta) ;    /* toCartesian returns a
 parmeterized rvalue */
I must ask, how would a statement like the second one be implemented? Maybe like this: x = r*cos(theta); y = r*sin(theta); Or perhaps like this: __temp1 = r*cos(theta); __temp2 = r*sin(theta); x = __temp1; y = __temp2; The latter would be less straightforward but would save the user from the bug of trying to swap variables with "(x, y) = (y, x);"
 4) Multiple return values are passed back via registers and stack in a
 well-defined way.
The same way that structs are returned, I presume. Another question: could the grammar be changed so that tuples would not need the enclosing ()'s, just like in someone's python example? Which is more readable, more maintainable, more comfortable? Alternative 1: int x; int y; (int, int) f(int, int); (x, y) = f(1, 2); Alternative 2: int x; int y; int, int f(int, int); x, y = f(1, 2); Yet another question: Is the following possible? int x, y; and what does it mean? Does it declare two integers, or is it half tuple, half declaration? Should I be able to write this: int x; x, int y = f(1, 2); // or maybe: (x, int y) = f(1, 2); Does this complicate parsing?
 This would make the code quite readable. But the cost,
 and the pre-requisite, would be to skip out-parameters
 entirely from the language.
Not necessary. This would certainly break existing code and also break C backward compatability (I think).
You most certainly do not mean this but something else, because the C language does not have out parameters. It would break compatibility, at least in spirit, with languages and conventions which use "in" and "out" declarations; IDL comes to mind. Finally, I agree that both multiple return values and tuples should be part of any modern programming language, and that they are much cleaner alternative than "out parameters" which is a contradiction in terms (not to mention that one man's in is another man's out). But it is also true that they don't come for free. First, the sequencing operator must be ditched and a proper workaround found. Then, the grammar must be revised to see whether the language can consume such a pervasive change (as the comma is used everywhere in language where lists exist, I expect that there may rise conflicts between the customary usages and tuple usage). Finally, the semantics of the tuples must be worked out with the proper care and attention so that will fit in the language as if originally designed for it, that they won't create any pitfalls, and that they won't break (too many) existing idioms. -Antti
Dec 03 2003
parent "Mark Brudnak" <malibrud provide.net> writes:
"Antti Sykäri" <jsykari gamma.hut.fi> wrote

<snip>

 I must ask, how would a statement like the second one be implemented?
 Maybe like this:

 x = r*cos(theta);
 y = r*sin(theta);

 Or perhaps like this:

 __temp1 = r*cos(theta); __temp2 = r*sin(theta);
 x = __temp1; y = __temp2;

 The latter would be less straightforward but would save the user from
 the bug of trying to swap variables with "(x, y) = (y, x);"
This would be legal, because the tuple-operator (,,,,,) would have *higher* precidence than the assignment operator. More importantly, each item in the RHS tuple would be evaluated. i.e. (re, im) = (exp(re)*cos(im), exp(re)*sin(im)) ; /* complex exponentiation */ Here exp(re) would be evaluated twice.
 4) Multiple return values are passed back via registers and stack in a
 well-defined way.
The same way that structs are returned, I presume.
Yes, exactly.
 Another question: could the grammar be changed so that tuples would not
 need the enclosing ()'s, just like in someone's python example?

 Which is more readable, more maintainable, more comfortable?

 Alternative 1:

     int x;
     int y;
     (int, int) f(int, int);

     (x, y) = f(1, 2);
Yes, very clear.
 Alternative 2:

     int x;
     int y;
     int, int f(int, int);

     x, y = f(1, 2);
No, it is not symmetric.
 Yet another question: Is the following possible?

     int x, y;

 and what does it mean? Does it declare two integers, or is it half
 tuple, half declaration? Should I be able to write this:

     int x;
     x, int y = f(1, 2); // or maybe:
No, it is not clear you have a tuple on the LHS.
     (x, int y) = f(1, 2);
Does D allow this in other areas? It is probably best to follow the D rules. Is it legal to write: int y = foo(1,2) ; <snip>
Dec 04 2003
prev sibling parent reply Commander Odama <Commander_member pathlink.com> writes:
With structs but you have the advantage of selecting whatever value you want
from a returned struct.

With multiple returns you have to consider all of the return values.
There is a slight advantage to a packaged multiple return.  This allows
you to package a set of values for return and keep the syntax simpler.  You can
select out of the return bundle whatever value you want.

The Java designers were very oversighted in removing structs.  Without structs
and without multiple returns there is no way to include or substitute multiple
returns.  So structs are useful without multiple return.

In article <bqgbtf$2726$1 digitaldaemon.com>, Mark J. Brudnak says...
"Makaan Kublai Kahn" <Makaan_member pathlink.com> wrote

 You can already do this.  You can return a struct I in C and C++.
 A struct can contain more than one value and encapsulate more than one
return
 of types.  It is better to return a struct of values than have a multiple
return
 for functions.  This is how it was intended to return multiple types.
Yes, but why should you have to define a structure just because you have to return two or three values rather than one? It is more code to write. The compiler knows all of the relevent information to define the structure implicitly. In other words the compiler is responsible for generating the struct. For example. FOR THE CALLER SIDE =================== D code as written: int x ; float y ; (x, y) = func(10, 3.14159, "foo") ; The compiler then compiles it as if I had written: int x ; float y ; { /* compiler generated block statement */ struct tempStruct { int var1 ; float var2 ; } tempStruct temp ; temp = func(10, 3.14159, "foo") ; x = temp.var1 ; y = temp.var2 ; } FOR THE CALLEE SIDE =================== D code as written: (int , float) = func(int a, float b, char [] c) { int result1 ; float result2 ; /* do stuff */ return( result1, result2 ) ; } The compiler then compiles it as if I had written: (int , float) = func(int a, float b, char [] c) { int result1 ; float result2 ; /* do stuff */ { /* compiler generated block statement */ struct tempStruct { int var1 ; float var2 ; } tempStruct temp ; temp.var1 = result1 ; temp.var2 = result2 ; return temp ; }/* end compiler generated block statement */ } This is also what happens to the aruments as well. They are stuffed into an implicitly defined structure consisting of either the registers and/or the stack in a well defined way. It is only natural to do the same thing in reverse. (i.e. use the registers and stack to pass back multiple return values in a well defined way. In this case our ficticious compiler used a struct, in an actual implementation it would use some registers and then the stack.) mark.
 A link for gcc is:  http://gcc.gnu.org/ml/gcc/1998-11/msg01087.html

 Here's an example from that link of returning a struct:

 ==================================================================
 -- z1.c --------------------------------------------------------

 struct s {
 int x;
 };

 struct s func (int y)
 {
 struct s xx;
 xx.x = y * 10;
 return xx;
 }

 -- z2.c --------------------------------------------------------

 struct s {
 int x;
 };

 extern struct s func (int y);

 void func2 (struct s x1, struct s x2)
 {
 printf ("%d %d\n", x1.x, x2.x);
 }


 int main ()
 {
 func2 (func (1), func (2));
 }
 ----------------------------------------------------------------


 On linux, compile z1.c with gcc 2.7.2 and z2.c with egcs and link
 them together.  The resulting program prints

 10 1

 rather than the expected

 10 20

 ==========================================================
Dec 06 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
I currently think it's a good idea to unify structs and parameter lists, and
tuples are basically anonymous structs with anonymous fields (only way to
get values back out is by pattern matching on types)

What is a parameter list anyhow but a shape of a collection of values at
some point in the flow of execution.  On the way into a function is a valid
point in the flow of execution.  So is the return, or should be.

A way to flexibly map structs to structs, or tuples to tuples, or tuples to
structs, would make this sort of thing very convenient.

I think D is aiming more toward status quo remaining largely C compatible.

Sean

"Commander Odama" <Commander_member pathlink.com> wrote in message
news:bqu23r$1io7$1 digitaldaemon.com...
 With structs but you have the advantage of selecting whatever value you
want
 from a returned struct.

 With multiple returns you have to consider all of the return values.
 There is a slight advantage to a packaged multiple return.  This allows
 you to package a set of values for return and keep the syntax simpler.
You can
 select out of the return bundle whatever value you want.

 The Java designers were very oversighted in removing structs.  Without
structs
 and without multiple returns there is no way to include or substitute
multiple
 returns.  So structs are useful without multiple return.
Dec 07 2003
parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Sean L. Palmer wrote:
 I currently think it's a good idea to unify structs and parameter lists, and
 tuples are basically anonymous structs with anonymous fields (only way to
 get values back out is by pattern matching on types)
This would requiere big changes in the language. Let the fields rather be named alphabetivally in their order: a,b,c,... This gives us 26 fields, which is usually quite enough - everything larger than 5 is better advised being a struct. I'm not sure Further fields are requiered, but then they could be named aa, ab, ac, ... zz. :) Also array indexing operator could be used as a notation for indexing fields by ordinal. This would in turn requiere a type inference assignment operator, which is a useful beast all by itself, and work in the cases where the current normal compiler can figure out the type of right hand side expression. instaed of : MyObjectType a = new MyObjectType(blahblah); you could write: a := new MyObjectType. for a function which returns multiple values: ret := FSinCos(); An unnamed strauct corresponding to type of ret would need to be implicitly declared just before use: struct trowaway_blahblah {real a; real b;} And the declaration of FSinCos should be: (real, real) FSinCos (real a); I believe this also reuieres that we change semantics of the comma operator, which would then return a tuple, instead of only the last value. This would nontheless allow the most common use of comma operator in C, which is to stuff up more into the for loop declaration. One possible problem is that this could make declaration of a tuple of tuples problematic...
 What is a parameter list anyhow but a shape of a collection of values at
 some point in the flow of execution.  On the way into a function is a valid
 point in the flow of execution.  So is the return, or should be.
True.
 A way to flexibly map structs to structs, or tuples to tuples, or tuples to
 structs, would make this sort of thing very convenient.
Sounds complicated.
 I think D is aiming more toward status quo remaining largely C compatible.
Hm... Who needs the curent comma operator anyway? -eye
Dec 07 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:bqve80$nk9$1 digitaldaemon.com...
 Sean L. Palmer wrote:
 I currently think it's a good idea to unify structs and parameter lists,
and
 tuples are basically anonymous structs with anonymous fields (only way
to
 get values back out is by pattern matching on types)
This would requiere big changes in the language. Let the fields rather be named alphabetivally in their order: a,b,c,... This gives us 26 fields, which is usually quite enough - everything larger than 5 is better advised being a struct. I'm not sure Further fields are requiered, but then they could be named aa, ab, ac, ... zz. :) Also array indexing operator could be used as a notation for indexing fields by ordinal.
As I said, D probably won't go for it. Your idea of using a thru z for the names isn't bad at all.
 This would in turn requiere a type inference assignment operator, which
 is a useful beast all by itself, and work in the cases where the current
 normal compiler can figure out the type of right hand side expression.

 instaed of :

 MyObjectType a = new MyObjectType(blahblah);

 you could write:

 a := new MyObjectType.

 for a function which returns multiple values:

 ret := FSinCos();

 An unnamed strauct corresponding to type of ret would need to be
 implicitly declared just before use:

 struct trowaway_blahblah {real a; real b;}

 And the declaration of FSinCos should be:

 (real, real) FSinCos (real a);
But if you do give the return values names, it would be more self-documenting and robust against later changes, say adding new return values or rearranging them.
 I believe this also reuieres that we change semantics of the comma
 operator, which would then return a tuple, instead of only the last
 value. This would nontheless allow the most common use of comma operator
 in C, which is to stuff up more into the for loop declaration.
I doubt that will happen. ;(
 A way to flexibly map structs to structs, or tuples to tuples, or tuples
to
 structs, would make this sort of thing very convenient.
Sounds complicated.
Haskell has something like this, where you can create a new data structure based on the contents of some other one, but providing overrides for some of the values. struct point { float x,y; } struct size { float width,height; } point mypoint; size distancetoorigin = mypoint { width = x, height = y }; Something like that, but the above syntax is not good.
 I think D is aiming more toward status quo remaining largely C
compatible.
 Hm... Who needs the curent comma operator anyway?
Nobody. It has very few uses, and those are questionable: Comma Operator Use 1: putting more than one assignment into a statement controlled by an if without having to use curly braces: if (foo > bar) x = foo, y = bar; which can easily be written thusly, no big deal: if (foo > bar) { x = foo; y = bar; } Comma Operator Use 2: doing some calculation before return int fn() { int x,y; return x = get_x(), y = get_y(), x*x + y*y + 1; } It would be clearer if written like this anyway: int fn() { int x = get_x(); int y = get_y(); return x*x + y*y + 1; } Comma Operator Use 3: for loops for (int i = 0, j = 1; i < 10 && j != i; ++i, j = i*3) printf("i = %d, j = %d\n", i, j); One could argue that this for loop is trying to do too much anyway. But the language could easily be extended in a slightly different way: allow statement blocks anywhere a statement is allowed, even in the 3rd section of a for loop: for (int i = 0, j = 1; i < 10 && j != i; { ++i; j = i*3; }) printf("i = %d, j = %d\n", i, j); That's a bad example because ++i, j = i*3 could be written j = ++i*3; Anyway the point is, there is not much the comma operator can do that can't easily be expressed some other, more legible way. It would be nice to have comma operator available for something truly useful, like tuples. Sean
Dec 07 2003
next sibling parent "Dan Liebgold" <dliebgold yahoo.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:br036k$1lis$1 digitaldaemon.com...
 Anyway the point is, there is not much the comma operator can do that
can't
 easily be expressed some other, more legible way.  It would be nice to
have
 comma operator available for something truly useful, like tuples.

 Sean
Indeed... I've only used the comma operator in for loops, and that was only in a dubious effort to save space. Tuples would be a much better use of the syntax, IMHO. Dan
Dec 08 2003
prev sibling parent Mark Brudnak <Mark_member pathlink.com> writes:
In article <br036k$1lis$1 digitaldaemon.com>, Sean L. Palmer says...
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:bqve80$nk9$1 digitaldaemon.com...
 Sean L. Palmer wrote:
 I currently think it's a good idea to unify structs and parameter lists,
and
 tuples are basically anonymous structs with anonymous fields (only way
to
 get values back out is by pattern matching on types)
This would requiere big changes in the language. Let the fields rather be named alphabetivally in their order: a,b,c,... This gives us 26 fields, which is usually quite enough - everything larger than 5 is better advised being a struct. I'm not sure Further fields are requiered, but then they could be named aa, ab, ac, ... zz. :) Also array indexing operator could be used as a notation for indexing fields by ordinal.
As I said, D probably won't go for it. Your idea of using a thru z for the names isn't bad at all.
 This would in turn requiere a type inference assignment operator, which
 is a useful beast all by itself, and work in the cases where the current
 normal compiler can figure out the type of right hand side expression.

 instaed of :

 MyObjectType a = new MyObjectType(blahblah);

 you could write:

 a := new MyObjectType.

 for a function which returns multiple values:

 ret := FSinCos();

 An unnamed strauct corresponding to type of ret would need to be
 implicitly declared just before use:

 struct trowaway_blahblah {real a; real b;}

 And the declaration of FSinCos should be:

 (real, real) FSinCos (real a);
But if you do give the return values names, it would be more self-documenting and robust against later changes, say adding new return values or rearranging them.
 I believe this also reuieres that we change semantics of the comma
 operator, which would then return a tuple, instead of only the last
 value. This would nontheless allow the most common use of comma operator
 in C, which is to stuff up more into the for loop declaration.
I doubt that will happen. ;(
 A way to flexibly map structs to structs, or tuples to tuples, or tuples
to
 structs, would make this sort of thing very convenient.
Sounds complicated.
Haskell has something like this, where you can create a new data structure based on the contents of some other one, but providing overrides for some of the values. struct point { float x,y; } struct size { float width,height; } point mypoint; size distancetoorigin = mypoint { width = x, height = y }; Something like that, but the above syntax is not good.
 I think D is aiming more toward status quo remaining largely C
compatible.
 Hm... Who needs the curent comma operator anyway?
Nobody. It has very few uses, and those are questionable: Comma Operator Use 1: putting more than one assignment into a statement controlled by an if without having to use curly braces: if (foo > bar) x = foo, y = bar; which can easily be written thusly, no big deal: if (foo > bar) { x = foo; y = bar; }
Also note that if tuples are entities on their own, then they can be both L-values and R-values of an assignment. So you could write. if (foo > bar) (x,y) = (foo,bar) ;
Comma Operator Use 2:  doing some calculation before return

int fn()
{
    int x,y;
    return x = get_x(), y = get_y(), x*x + y*y + 1;
}

It would be clearer if written like this anyway:

int fn()
{
    int x = get_x();
    int y = get_y();
    return x*x + y*y + 1;
}
Or you could write it with tuples: int fn() { (int x, int y) = ( get_x(), get_y() ) ; return x*x + y*y + 1; } ..or better yet... int fn() { (int x, int y) = get_x_and_y() ; return x*x + y*y + 1; }
Comma Operator Use 3:  for loops

for (int i = 0, j = 1; i < 10 && j != i; ++i, j = i*3)
    printf("i = %d, j = %d\n", i, j);

One could argue that this for loop is trying to do too much anyway.  But the
language could easily be extended in a slightly different way:  allow
statement blocks anywhere a statement is allowed, even in the 3rd section of
a for loop:

for (int i = 0, j = 1; i < 10 && j != i; { ++i; j = i*3; })
    printf("i = %d, j = %d\n", i, j);

That's a bad example because ++i, j = i*3 could be written j = ++i*3;
Or using tuples... for ( (int i, int j) = (0, 1) ; i < 10 && j != i ; (i,j) = ( i+1, (i+1)*3 ) ) printf("i = %d, j = %d\n", i, j);
Anyway the point is, there is not much the comma operator can do that can't
easily be expressed some other, more legible way.  It would be nice to have
comma operator available for something truly useful, like tuples.

Sean
Dec 09 2003
prev sibling parent Heretic <Heretic_member pathlink.com> writes:
 (a) = someFunc(10);

 Further to that, how would nested functions work?
 (int) = someFunc(int, int, int)
 (int, int, int) = foo(float)

 (a) = someFunc(foo(10.0));
Nesting for the time being should not be allowed. The function should return a parameterized rvalue ready for assignment to a suitable lvalue. If a compelling case arises this could be explored.
How bout this: (a) = someFunc( (int, int, int) = foo(float) ) ? could just makin it more explicit work ?
Dec 02 2003