gusl: (Default)
[personal profile] gusl
PL people,

I'd like to have a language that allows a double assignment like this:

radius * angle =  convert (x,y);

which assigns two local variables 'radius' and 'angle' to the (double) return value of convert.


The declaration for the 'convert' function is as follows:
double * double convert (double x, double y){
 return makeRadius(x,y) * makeAngle(x,y);
}

(We need a better choice than '*', since that usually means multiplication)


You could also have call-dispatching on the output type, not just the input types. If you had two functions named 'convert' with the same input types, you would call the one that matches the type of the variable you're assigning to.

This would be a useful pattern, and if I had it, I would write fewer functions with side-effects (which in Java is often necessary for efficiency purposes).


* having small functions
* having no functions with side-effects
* efficiency
In Java, you have to pick 2.

(no subject)

Date: 2007-02-05 04:32 pm (UTC)
From: [identity profile] jcreed.livejournal.com
Uh... We ML/Haskell/etc. programmers have taken this feature (i.e. tuple types) for granted for years.

(no subject)

Date: 2007-02-05 04:40 pm (UTC)
ikeepaleopard: (Default)
From: [personal profile] ikeepaleopard
Even stupidly typed languages like python have this feature.

I often hack up a Pair class when I'm stuck in java. It's much less painful if you use java 1.5
class Pair
[Error: Irreparable invalid markup ('<a,>') in entry. Owner must fix manually. Raw contents below.]

Even stupidly typed languages like python have this feature.

I often hack up a Pair class when I'm stuck in java. It's much less painful if you use java 1.5
class Pair<A, B>{
public Pair(A a, B b){
fst = a; snd = b;
}
A getFst(){return fst};
B getSnd(){return snd};
}

(no subject)

Date: 2007-02-05 04:42 pm (UTC)
ikeepaleopard: (Default)
From: [personal profile] ikeepaleopard
Err, pretend I put in instance variable declarations and formatted that correctly.

(no subject)

Date: 2007-02-05 04:48 pm (UTC)
From: [identity profile] jcreed.livejournal.com
e.g.
- fun convert p = let 
                   fun radius (x,y) = Math.sqrt(x * x + y * y)
                  in
                   (radius p, Math.atan2 p)
                  end;
val convert = fn : real * real -> real * real

(no subject)

Date: 2007-02-05 05:01 pm (UTC)
From: [identity profile] en-ki.livejournal.com
In Ruby, you'd just return an array:

$ ruby -e 'def f; [1,2]; end; a, b = f(); p a, b'
1
2

(no subject)

Date: 2007-02-05 05:30 pm (UTC)
From: [identity profile] xuande.livejournal.com
In Perl, you could return a list:
sub convert
{
    return makeRadius($_[0],$_[1]),  makeAngle($_[0],$_[1]);
}

(Yes, Perl has an ugly syntax for retrieving function arguments.)

While Perl doesn't exactly do call-dispatching based on the return type of a function, you can find out from inside a function what sort of return value a given call is expecting and act appropriately:
sub convert
{
    if (wantarray()) {
        # List expected
        return makeRadius($_[0],$_[1]),  makeAngle($_[0],$_[1]);
    } else {
        # Single (scalar) value or no (void) value expected
        return somethingElse($_[0],$_[1]);
    }
}

You can also tell if you're being called in a scalar or void context, but I forget how ATM.

IIRC, Common Lisp is also set up to handle multiple return values, but accessing them was also kind of clunky.

(no subject)

Date: 2007-02-05 06:20 pm (UTC)

(no subject)

Date: 2007-02-05 06:30 pm (UTC)
ikeepaleopard: (Default)
From: [personal profile] ikeepaleopard
I'd strongly discourage branching on expected return type, that seems like a very confusing issue in the presence of subtyping. Additionally, if you know what the type is, you can just call a different function.

(no subject)

Date: 2007-02-05 07:49 pm (UTC)
From: [identity profile] gwillen.livejournal.com
Common Lisp can handle multiple return values using an additional mechanism, above and beyond just returning a list (which is also supported, and much easier.)

(no subject)

Date: 2007-02-05 07:50 pm (UTC)
From: [identity profile] gwillen.livejournal.com
I feel like there's some good reason that C (for example) doesn't dispatch on the return type of a function when handling overloading. I don't actually know what the reason is, though....

(no subject)

Date: 2007-02-05 07:56 pm (UTC)
ikeepaleopard: (Default)
From: [personal profile] ikeepaleopard
so, first C doesn't have overloading, second
Which one do you call?

void* foo();

bar* foo();

int main(){
void* baz = (void*)foo();
}

(no subject)

Date: 2007-02-05 07:58 pm (UTC)
From: [identity profile] roseandsigil.livejournal.com
For example.

If you have

int foo(); //both of these have some crazy side effect
float foo(); //both of these have some crazy side effect

foo();

You can't tell what the programmer meant easily. Sure you could set up rules about which one it is, but that's another complication, and really an unecessary one.

And even if you actually use the return value, in the presence of C++'s multiple inheritance you really can't do much more than cry.

(no subject)

Date: 2007-02-05 08:04 pm (UTC)
From: [identity profile] dachte.livejournal.com
I would guess that it's because sometimes people ignore the return context to a function, and sometimes they pay attention -- it would be kind of weird to have a function behave differently depending on if it's called in void context or not. OTOH, it might be an interesting way to allow for policy-based exception handling.

(no subject)

Date: 2007-02-05 08:10 pm (UTC)
From: [identity profile] bhudson.livejournal.com
IIRC, there is a java.util.Pair class, must like the STL pair class.

Both are fucking painful to use, sadly.

(no subject)

Date: 2007-02-05 08:12 pm (UTC)
From: [identity profile] bhudson.livejournal.com
Oh I so hate the scalar/list context stuff. I mean, it's a bit useful from the point of view of the callee, but the caller always has to be careful about what will come out.

(no subject)

Date: 2007-02-05 08:14 pm (UTC)
ikeepaleopard: (Default)
From: [personal profile] ikeepaleopard
I've looked before and I just checked again it's not in java.util or java.lang.

(no subject)

Date: 2007-02-05 08:18 pm (UTC)
From: [identity profile] bhudson.livejournal.com
Huh; the web has ten billion hits for "java.util.Pair" -- but all of them are begging Sun to make this class exist. Lame.

(no subject)

Date: 2007-02-05 08:19 pm (UTC)
From: [identity profile] bhudson.livejournal.com
(where by "ten billion" I mean "nine").

(no subject)

Date: 2007-02-05 08:21 pm (UTC)
From: [identity profile] bhudson.livejournal.com
In C/C++ (after about 1990 -- before that, you needed to have return values be a basic type or a pointer, because it was way too hard to make the compiler do it), you can do
struct RadiusAngle {
double radius;
double angle;
};

RadiusAngle convert(double x, double y) {
RadiusAngle ra;
ra.radius = ...;
ra.angle = ...;
return ra;
}

In Java, you can do similar things, except you need to make a class.

Both methods are cumbersome in that you must explicitely define and name the type; as mentioned, there's the pair template idiom to get around it if you have just a pair (you can use recursive pairs to get triples etc, but eventually it all turns to rotted apples and you should have defined a type).

This is part of why these languages suck.

(no subject)

Date: 2007-02-05 08:54 pm (UTC)
From: [identity profile] cdtwigg.livejournal.com
STL pair isn't that bad. It's just missing the syntactic sugar of ML.

(no subject)

Date: 2007-02-05 10:58 pm (UTC)
From: [identity profile] dachte.livejournal.com
Umm... forgive me if being half-frozen is making me dumb, but won't that be a dangling reference you're passing back?

(no subject)

Date: 2007-02-06 12:21 am (UTC)
From: [identity profile] bhudson.livejournal.com
Luckily, dumb people can still type -- imagine if this were all being verbally communicated!

But no, there's no dangling reference. I'm just returning a 128-bit object rather than a 64- or 32-bit one. The compiler may use any method it pleases to do this; typically, it'll be on the stack for x86, and through registers on basically all other machines.

(no subject)

Date: 2007-02-06 12:27 am (UTC)
From: [identity profile] bhudson.livejournal.com
Compare: making the pair:
SML - (radius p, Math.atan2 p)
C++ - make_pair(radius p, Math.atan2 p)
Small difference.

Using the pair:
SML - val (r, theta) = convert p
C++ - pair<double,double> rtheta = convert p; double r = rtheta.first; double theta = rtheta.second;
Ugh.

Then, we could repeat the exercise for a triple for true ugliness.

(no subject)

Date: 2007-02-06 12:28 am (UTC)
From: [identity profile] bhudson.livejournal.com
So, yes, it's "just missing syntactic sugar."

(no subject)

Date: 2007-02-06 05:37 am (UTC)
From: [identity profile] simrob.livejournal.com
What's nine orders of magnitued between friends?

(no subject)

Date: 2007-02-06 05:38 am (UTC)
From: [identity profile] simrob.livejournal.com
Pair (test,test)

(no subject)

Date: 2007-02-06 06:16 am (UTC)
From: [identity profile] spoonless.livejournal.com
In perl, you can return multiple variables from a function like this:

($factor_A,$factor_B) = factor(largeprime1*largeprime2);

I think the same goes for Mathematica and Matlab, although sometimes I get them confused so maybe only one of them does this.

(no subject)

Date: 2007-02-06 03:20 pm (UTC)
From: [identity profile] cdtwigg.livejournal.com
The reason it's called "syntactic sugar" is that it can always be added to the language later:
double r, theta;
boost::tie(r, theta) = convert(p);

(no subject)

Date: 2007-02-06 03:28 pm (UTC)
From: [identity profile] cdtwigg.livejournal.com
Also taken care of, as (again) it's syntactic sugar:
boost::tuple<float, double, int&rt;
There are limits to how far you should push this "unnamed tuple" business though anyway as you are going to have to carefully document the order of the things that are returned and the consumer of the function is going to have to remember them. Do you really want to return a tuple of 10 floats? At some point, you just have to break down and define a struct with named fields, or else do the old C-style thing and take pointers to variables in the calling sequence.

(no subject)

Date: 2007-02-06 03:28 pm (UTC)
From: [identity profile] cdtwigg.livejournal.com
obviously should be > not &rt;

(no subject)

Date: 2007-02-06 04:08 pm (UTC)
From: [identity profile] bhudson.livejournal.com
This boost thing is kind of nice.

The SML way of doing the record thing (which I often prefer to tuples, for the reasons you mentioned) is:
to create one: { a=v1, b=v2, c=v3 }
to receive one: { a,b,c } = ...

February 2020

S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags