|
Archives
D Programming
D
D.gnu
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
|
D - Other Modern Features
↑ ↓ ← → "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
↑ ↓ ← → "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,
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
instantiates the concrete derived class and returns a reference to it.
subsequent calls are handled directly by the plugin.
That seems like it would be a library feature. Would you care to write one?
↑ ↓ ← → "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
and catalogues all available plugins which have the proper interface.
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
instantiates the concrete derived class and returns a reference to it.
subsequent calls are handled directly by the plugin.
That seems like it would be a library feature.
Most definitely
↑ ↓ ← → "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
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,
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
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
and catalogues all available plugins which have the proper interface.
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
instantiates the concrete derived class and returns a reference to it.
subsequent calls are handled directly by the plugin.
That seems like it would be a library feature. Would you care to write
↑ ↓ ← → "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
that implemented this.
C
I am surprised that Java or C# did not incorporate this feature. The idea
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 ! */
↑ ↓ ← → Berin Loritsch <bloritsch d-haven.org> writes:
Mark Brudnak wrote:
I am surprised that Java or C# did not incorporate this feature. The idea
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 );
???
↑ ↓ ← → "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...
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.
↑ ↓ ← → 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.
↑ ↓ ← → "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,
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
good reasons.
It's a stretch for me just to accept multiple return values--when you
differing methods based on return type, things get really messy really
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.
↑ ↓ ← → 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.
↑ ↓ ← → 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.
↑ ↓ ← → 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...
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.
↑ ↓ ← → "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...
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.
↑ ↓ ← → 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.
↑ ↓ ← → "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
↑ ↓ ← → "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
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
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
and decreasing time to market. And that's what makes or breaks projects
companies. (Unless you've been through the rise and fall of a few
that's not so obvious.)
--
Steve Maillet (eMVP)
Entelechy Consulting
smaillet_AT_EntelechyConsulting_DOT_com
↑ ↓ ← → "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
↑ ↓ ← → "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
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
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
↑ ↓ ← → "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
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.
↑ ↓ ← → 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
↑ ↓ ← → 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
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.
↑ ↓ ← → "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
chnaged too, to accept multiple parameters). else, using a more
approach, i.e. returning the output parameters with the last value they
before quiting the fcn. will simply change some fondamental concepts.
-in Matlab, one feature missing is the non-reference parameters transfer.
means that, for each function affecting x you must write x=domsmthngto(x).
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,
the same can be done with D, although i agree I would LOVE to see a
that implemented this.
I'd rather see it in the language, but if it's not I've no doubt it'll
its way in when the templates get a serious shake.
↑ ↓ ← → 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
chnaged too, to accept multiple parameters). else, using a more
approach, i.e. returning the output parameters with the last value they
before quiting the fcn. will simply change some fondamental concepts.
-in Matlab, one feature missing is the non-reference parameters transfer.
means that, for each function affecting x you must write x=domsmthngto(x).
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,
the same can be done with D, although i agree I would LOVE to see a
that implemented this.
I'd rather see it in the language, but if it's not I've no doubt it'll
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
==========================================================
↑ ↓ ← → "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
of types. It is better to return a struct of values than have a multiple
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
==========================================================
↑ ↓ ← → 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.
↑ ↓ ← → "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
↑ ↓ ← → "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
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
the number of inputs and outputs.
Multiple outputs are used very often in MATLAB code. varargout is used
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.
↑ ↓ ← → 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.
↑ ↓ ← → "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).
also defines the variables "nargin" and "nargout" in the function body
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
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.
↑ ↓ ← → 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
↑ ↓ ← → "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
↑ ↓ ← → "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
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.
↑ ↓ ← → 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?
↑ ↓ ← → "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
↑ ↓ ← → 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...)
↑ ↓ ← → "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
↑ ↓ ← → 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;
}
↑ ↓ ← → "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
↑ ↓ ← → 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
↑ ↓ ← → "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
Yes, you could and IMHO you SHOULD. The beauty of that is that
language constructs allow you to do so already! Templates/generics allow
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
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
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
"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
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
multiple return values the compiler will have to do that underneath
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.
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
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
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
↑ ↓ ← → "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)).
This would make the code quite readable. But the cost,
and the pre-requisite, would be to skip out-parameters
entirely from the language.
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.
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.
↑ ↓ ← → 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.
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
↑ ↓ ← → "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>
↑ ↓ ← → 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
of types. It is better to return a struct of values than have a multiple
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
==========================================================
↑ ↓ ← → "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
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.
select out of the return bundle whatever value you want.
The Java designers were very oversighted in removing structs. Without
and without multiple returns there is no way to include or substitute
returns. So structs are useful without multiple return.
↑ ↓ ← → 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
↑ ↓ ← → "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,
tuples are basically anonymous structs with anonymous fields (only way
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
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
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
↑ ↓ ← → "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
easily be expressed some other, more legible way. It would be nice to
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
↑ ↓ ← → 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,
tuples are basically anonymous structs with anonymous fields (only way
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
|