I had a calculation that effectively had half a dozen outputs. When I
originally wrote it, I invented a method for each result that would
calculate just that result. This turned out be a dumb idea. It
caused repeated logic and exploded the complexity.
What I have done now had greatly simplified the code. I have one
method that provides all the inputs and that calculates everything.
Then all the result-grabber methods are just simple getters.
The only downside is I must allocate a calculating object to hold the
results.
It has always seemed odd to me that most computer languages allow many
inputs but only one output. Plumbing and wires don't behave that way.
--
Roedy Green Canadian Mind Products
http://mindprod.com
If you think it’s expensive to hire a professional to do the job, wait until you hire an amateur.
~ Red Adair
|
|
0
|
|
|
|
Reply
|
Roedy
|
3/25/2011 7:22:08 AM |
|
In message <kbgoo6dfrkh58r3ogel9nb6rekrs258it2@4ax.com>, Roedy Green wrote:
> It has always seemed odd to me that most computer languages allow many
> inputs but only one output. Plumbing and wires don't behave that way.
There is the LISP way, with multivalued results which are not the same thing
as tuples. Or there is the Python way, where a function can return a tuple
which can be directly assigned to individual variables.
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/25/2011 9:45:59 AM
|
|
Lawrence D'Oliveiro <ldo@geek-central.gen.new_zealand> wrote:
> In message <kbgoo6dfrkh58r3ogel9nb6rekrs258it2@4ax.com>, Roedy Green wrote:
>
>> It has always seemed odd to me that most computer languages allow many
>> inputs but only one output. Plumbing and wires don't behave that way.
>
> There is the LISP way, with multivalued results which are not the same thing
> as tuples. Or there is the Python way, where a function can return a tuple
> which can be directly assigned to individual variables.
And there's the right way (yes, my biases are showing, I know):
procedure Example
(A : in Float;
B : in out Float;
C : out Float)
--
Leif Roar Moldskred
|
|
0
|
|
|
|
Reply
|
Leif
|
3/25/2011 9:52:29 AM
|
|
In message <7v-dnf0DVrdA-BHQnZ2dnUVZ8783t52d@telenor.com>, Leif Roar
Moldskred wrote:
> Lawrence D'Oliveiro <ldo@geek-central.gen.new_zealand> wrote:
>
>> In message <kbgoo6dfrkh58r3ogel9nb6rekrs258it2@4ax.com>, Roedy Green
>> wrote:
>>
>>> It has always seemed odd to me that most computer languages allow many
>>> inputs but only one output. Plumbing and wires don't behave that way.
>>
>> There is the LISP way, with multivalued results which are not the same
>> thing as tuples. Or there is the Python way, where a function can return
>> a tuple which can be directly assigned to individual variables.
>
> And there's the right way (yes, my biases are showing, I know):
>
> procedure Example
> (A : in Float;
> B : in out Float;
> C : out Float)
But that’s procedural, not functional.
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/25/2011 11:01:16 AM
|
|
Lawrence D'Oliveiro wrote:
> In message<kbgoo6dfrkh58r3ogel9nb6rekrs258it2@4ax.com>, Roedy Green wrote:
>
>> It has always seemed odd to me that most computer languages allow many
>> inputs but only one output. Plumbing and wires don't behave that way.
>
> There is the LISP way, with multivalued results which are not the same thing
> as tuples. Or there is the Python way, where a function can return a tuple
> which can be directly assigned to individual variables.
I believe that's an example of a false dichotomy.
BugBear
|
|
0
|
|
|
|
Reply
|
bugbear
|
3/25/2011 11:19:54 AM
|
|
Lawrence D'Oliveiro <ldo@geek-central.gen.new_zealand> wrote:
>
> But that’s procedural, not functional.
Well, yes. It would be a silly way to do it for a functional programming
language. (Then again, it can be argued that for a functional programming
language it's silly to support multiple return values at all: it does go
rather against the grain of the whole "function" thing, after all.)
--
Leif Roar Moldskred
|
|
0
|
|
|
|
Reply
|
leifm1143 (162)
|
3/25/2011 11:51:34 AM
|
|
Roedy Green wrote:
> It has always seemed odd to me that most computer languages allow many
> inputs but only one output. Plumbing and wires don't behave that way.
Good thing Java allows you to return multiple outputs by putting them into a
holder type, then.
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
|
|
0
|
|
|
|
Reply
|
noone7 (3512)
|
3/25/2011 11:51:34 AM
|
|
On 3/25/2011 3:22 AM, Roedy Green wrote:
> I had a calculation that effectively had half a dozen outputs. When I
> originally wrote it, I invented a method for each result that would
> calculate just that result. This turned out be a dumb idea. It
> caused repeated logic and exploded the complexity.
>
> What I have done now had greatly simplified the code. I have one
> method that provides all the inputs and that calculates everything.
> Then all the result-grabber methods are just simple getters.
>
> The only downside is I must allocate a calculating object to hold the
> results.
>
> It has always seemed odd to me that most computer languages allow many
> inputs but only one output. Plumbing and wires don't behave that way.
It seems to me a matter of notational convenience more than
anything else. We write `q = y / z', a calculation with an
intentional but superficial resemblance to a mathematical
expression, and there's no place to describe what to do with
the division's remainder, a sometimes useful quantity that was
computed as a by-product. `(q,r) = y / z', maybe? It mightn't
be too awkward for quotient-and-remainder, but using the same
pattern for "half a dozen outputs" would be cumbersome and
error-prone, I think, You'd want something that could attach
names to the pieces of the assignment target, and match them
up with names in the expression value. Something like
int r, g, b;
(r.red, g.green, b.blue) = backgroundColor; // drop alpha
FWIW, at least one dialect of Lisp supports multi-valued
expressions. You can write the moral equivalent of
x = f(a,b,c)
if you only care about the "principal" returned value, or the
moral equivalent of
(x,y) = f(a,b,c)
if you want the ancillary value(s) as well.
--
Eric Sosman
esosman@ieee-dot-org.invalid
|
|
0
|
|
|
|
Reply
|
Eric
|
3/25/2011 12:04:08 PM
|
|
In message <JMednbE0j8VbHBHQnZ2dnUVZ876dnZ2d@telenor.com>, Leif Roar
Moldskred wrote:
> (Then again, it can be argued that for a functional programming
> language it's silly to support multiple return values at all: it does go
> rather against the grain of the whole "function" thing, after all.)
Why?
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/25/2011 1:11:04 PM
|
|
In message <kbgoo6dfrkh58r3ogel9nb6rekrs258it2@4ax.com>, Roedy Green wrote:
> It has always seemed odd to me that most computer languages allow many
> inputs but only one output. Plumbing and wires don't behave that way.
If you want to be able to express arbitrary dataflow connections, the only
notationss I’m aware of that can deal with that are stack-based (e.g.
POP-11, FORTH, PostScript). But such notations are notoriously error-prone.
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/25/2011 1:12:44 PM
|
|
On Fri, 25 Mar 2011 08:04:08 -0400, Eric Sosman wrote:
> On 3/25/2011 3:22 AM, Roedy Green wrote:
>> I had a calculation that effectively had half a dozen outputs. When I
>> originally wrote it, I invented a method for each result that would
>> calculate just that result. This turned out be a dumb idea. It caused
>> repeated logic and exploded the complexity.
>>
>> What I have done now had greatly simplified the code. I have one method
>> that provides all the inputs and that calculates everything. Then all
>> the result-grabber methods are just simple getters.
>>
>> The only downside is I must allocate a calculating object to hold the
>> results.
>>
>> It has always seemed odd to me that most computer languages allow many
>> inputs but only one output. Plumbing and wires don't behave that way.
>
> It seems to me a matter of notational convenience more than
> anything else. We write `q = y / z', a calculation with an intentional
> but superficial resemblance to a mathematical expression, and there's no
> place to describe what to do with the division's remainder, a sometimes
> useful quantity that was computed as a by-product. `(q,r) = y / z',
> maybe?
Clojure, a JVM language that can use Java libraries and be called from
Java, has something like this:
(defn divide
"Returns [q r] with the property that qy + r = x and
0 <= r < abs(y)."
[x y]
(cond
(and (< x 0) (< y 0))
(let [[q r] (divide (- x) (- y))]
[(inc q) (- (- y) r)])
(< x 0)
(let [[q r] (divide (- x) y)]
[(dec (- q)) (- y r)])
(< y 0)
(let [[q r] (divide x (- y))]
[(- q) r])
:else
(loop [q 0 r x]
(if (> r y)
(recur (inc q) (- r y))
[q r]))))
(let [[q r] (divide a b)]
(do-stuff-with q r))
(Of course, there are better ways to do integer division; this was just
an example. Converting polar to Cartesian coordinates and back
simultaneously would be a more realistic use case. Then again, (juxt quot
rem) doesn't quite give the properties of the divide defined above -- the
remainder ends up negative if x is negative.)
But it doesn't just push the multiple returns on the stack (as the JVM
calling convention doesn't seem to allow that); it bundles them into a
heap-allocated object (a vector, basically an unmodifiable ArrayList) and
returns that. You could even do
(let [v (divide a b)]
(do-array-list-stuff-with v))
if you wanted to.
> FWIW, at least one dialect of Lisp supports multi-valued
> expressions. You can write the moral equivalent of
>
> x = f(a,b,c)
>
> if you only care about the "principal" returned value, or the moral
> equivalent of
>
> (x,y) = f(a,b,c)
>
> if you want the ancillary value(s) as well.
Common Lisp has this, with somewhat warty syntax here and there. It uses
the stack. You may also be able to use lists/vectors and destructuring as
in Clojure, but that will again involve heap allocation of conses/vectors.
I don't see any way to avoid the holder object on the JVM. Clojure's
destructuring and vector literals with runtime-variable elements may
sugar up the syntax a bit but that's it.
|
|
0
|
|
|
|
Reply
|
Ken
|
3/25/2011 1:41:14 PM
|
|
On 03/25/2011 03:22 AM, Roedy Green wrote:
> It has always seemed odd to me that most computer languages allow many
> inputs but only one output. Plumbing and wires don't behave that way.
But mathematical functions return only one value; if you want to return
more, you have to specify Cartesian products... which, to a large
degree, is precisely what you do when you make holder objects. If you
view programming languages as a descendant of mathematical notation,
then this viewpoint makes logical sense.
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
|
|
0
|
|
|
|
Reply
|
Joshua
|
3/25/2011 1:57:58 PM
|
|
Lawrence D'Oliveiro <ldo@geek-central.gen.new_zealand> wrote:
> In message <JMednbE0j8VbHBHQnZ2dnUVZ876dnZ2d@telenor.com>, Leif Roar
> Moldskred wrote:
>
>> (Then again, it can be argued that for a functional programming
>> language it's silly to support multiple return values at all: it does go
>> rather against the grain of the whole "function" thing, after all.)
>
> Why?
Because functional programming tries (by and large) to treat computation
as progressing through mathematical(ish) functions -- which are a mapping
from one or more inputs to a single result. Multiple return values veers
from this mental model.
--
Leif Roar Moldskred
|
|
0
|
|
|
|
Reply
|
Leif
|
3/25/2011 2:20:37 PM
|
|
Leif Roar Moldskred wrote:
> Lawrence D'Oliveiro<ldo@geek-central.gen.new_zealand> wrote:
>> In message<JMednbE0j8VbHBHQnZ2dnUVZ876dnZ2d@telenor.com>, Leif Roar
>> Moldskred wrote:
>>
>>> (Then again, it can be argued that for a functional programming
>>> language it's silly to support multiple return values at all: it does go
>>> rather against the grain of the whole "function" thing, after all.)
>>
>> Why?
>
> Because functional programming tries (by and large) to treat computation
> as progressing through mathematical(ish) functions -- which are a mapping
> from one or more inputs to a single result. Multiple return values veers
> from this mental model.
Heh. Many functional programmers then end up building
quite large structures in passed parameters,
and then returning the whole thing.
It's still functional, but when a single "value"
can be a LISP list, it's not as single
as you first thought ;-)
BugBear
|
|
0
|
|
|
|
Reply
|
bugbear
|
3/25/2011 2:32:50 PM
|
|
On Fri, 25 Mar 2011 14:32:50 +0000, bugbear wrote:
> Leif Roar Moldskred wrote:
>> Lawrence D'Oliveiro<ldo@geek-central.gen.new_zealand> wrote:
>>> In message<JMednbE0j8VbHBHQnZ2dnUVZ876dnZ2d@telenor.com>, Leif Roar
>>> Moldskred wrote:
>>>
>>>> (Then again, it can be argued that for a functional programming
>>>> language it's silly to support multiple return values at all: it does
>>>> go rather against the grain of the whole "function" thing, after
>>>> all.)
>>>
>>> Why?
>>
>> Because functional programming tries (by and large) to treat
>> computation as progressing through mathematical(ish) functions -- which
>> are a mapping from one or more inputs to a single result. Multiple
>> return values veers from this mental model.
>
> Heh. Many functional programmers then end up building quite large
> structures in passed parameters, and then returning the whole thing.
>
> It's still functional, but when a single "value" can be a LISP list,
> it's not as single as you first thought ;-)
And on the mathematical side there are vector-valued functions.
Another trick is returning hashes with key/value pairs -- mathematically
equivalent to a function whose value is another function, which latter
just happens to be defined pointwise. Especially in Clojure, where hashes
can be invoked like functions and behave as pointwise defined functions
on their keys, returning the associated values.
|
|
0
|
|
|
|
Reply
|
Ken
|
3/25/2011 3:01:32 PM
|
|
On 3/25/2011 12:22 AM, Roedy Green wrote:
> I had a calculation that effectively had half a dozen outputs. When I
> originally wrote it, I invented a method for each result that would
> calculate just that result. This turned out be a dumb idea. It
> caused repeated logic and exploded the complexity.
>
> What I have done now had greatly simplified the code. I have one
> method that provides all the inputs and that calculates everything.
I think it would elucidate your refactoring pattern more if you included
an example. What you did post is very general:
"I made a thing. Then I refactored and it was better."
Yay?
|
|
0
|
|
|
|
Reply
|
markspace
|
3/25/2011 4:43:56 PM
|
|
On 11-03-25 10:12 AM, Lawrence D'Oliveiro wrote:
> In message <kbgoo6dfrkh58r3ogel9nb6rekrs258it2@4ax.com>, Roedy Green wrote:
>
>> It has always seemed odd to me that most computer languages allow many
>> inputs but only one output. Plumbing and wires don't behave that way.
>
> If you want to be able to express arbitrary dataflow connections, the only
> notationss I’m aware of that can deal with that are stack-based (e.g.
> POP-11, FORTH, PostScript). But such notations are notoriously error-prone.
If you want to do dataflow then the best way to do it is using a
dataflow language. I've used a few of them, including LabVIEW and
Prograph CPX (which latter was pretty awesome actually). And one can
argue that stitching together UNIX tools with tees and pipes and
redirects is a form of dataflow.
AHS
--
That's not the recollection that I recall...All this information is
certainly in the hands of the auditor and we certainly await his report
to indicate what he deems has occurred.
-- Halifax, Nova Scotia mayor Peter Kelly, who is currently deeply in
the shit
|
|
0
|
|
|
|
Reply
|
Arved
|
3/25/2011 9:09:08 PM
|
|
In message <Vv7jp.1732$in3.386@newsfe17.iad>, Arved Sandstrom wrote:
> If you want to do dataflow then the best way to do it is using a
> dataflow language. I've used a few of them, including LabVIEW and
> Prograph CPX (which latter was pretty awesome actually).
You mean graphical languages? I’m not sure how well they scale. Also there’s
the problem that standard source manipulations like diff/patch and merge are
lacking.
> And one can argue that stitching together UNIX tools with tees and pipes
> and redirects is a form of dataflow.
That can express fan-out, but I don’t think it can express subsequent fan-in
from that fan-out.
The standard solution to this is to introduce names for the connections
somewhere. Which basically brings us right back to functional programming.
|
|
0
|
|
|
|
Reply
|
ldo (2144)
|
3/26/2011 2:39:05 AM
|
|
In message <imi0cq$ah4$1@dont-email.me>, Eric Sosman wrote:
> You'd want something that could attach names to the pieces of the
> assignment target, and match them up with names in the expression value.
> Something like
>
> int r, g, b;
> (r.red, g.green, b.blue) = backgroundColor; // drop alpha
In Python you can write
r, g, b = (getattr(backgroundColor, f) for f in ("red", "green", "blue"))
But really, is it such a big deal? In conventional languages like C we
happily write
q = y / z;
r = y % z;
and leave it to the compiler to do the dataflow analysis for us.
|
|
0
|
|
|
|
Reply
|
ldo (2144)
|
3/26/2011 2:44:44 AM
|
|
On Fri, 25 Mar 2011 07:51:34 -0400, Lew <noone@lewscanon.com> wrote,
quoted or indirectly quoted someone who said :
>Good thing Java allows you to return multiple outputs by putting them into a
>holder type, then.
You could implement a language with a single input too. You must
construct an artificial (that has no meaning other than holder for
some function) object if you need more than one parameter. Gaak! you
say. How inconvenient! That's how I feel about requiring dummy holder
objects for multiple outputs.
What is so different about in input and output? Why should they be
treated so differently? In a beautiful language the syntax should as
parallel as possible.
Underneath, at the JVM level, they could be treated FORTH style, just
have the caller push the parms on the stack and have the callee pop
the inputs and push the results to the stack, or perhaps use two
stacks, one for inputs and one for outputs.
--
Roedy Green Canadian Mind Products
http://mindprod.com
There are only two industries that refer to their customers as "users".
~ Edward Tufte
|
|
0
|
|
|
|
Reply
|
Roedy
|
3/26/2011 4:43:20 AM
|
|
On Fri, 25 Mar 2011 09:43:56 -0700, markspace <-@.> wrote, quoted or
indirectly quoted someone who said :
>I think it would elucidate your refactoring pattern more if you included
>an example. What you did post is very general:
You can see the new code at
http://mindprod.com/applet/canadiantax.html
The class in question is CalculateCanadianTaxes
The outputs include GST, HST, PST tax rates, GST, HST, PST tax
amounts, total tax, and total payable.
--
Roedy Green Canadian Mind Products
http://mindprod.com
There are only two industries that refer to their customers as "users".
~ Edward Tufte
|
|
0
|
|
|
|
Reply
|
Roedy
|
3/26/2011 4:50:33 AM
|
|
On 11-03-25 11:39 PM, Lawrence D'Oliveiro wrote:
> In message <Vv7jp.1732$in3.386@newsfe17.iad>, Arved Sandstrom wrote:
>
>> If you want to do dataflow then the best way to do it is using a
>> dataflow language. I've used a few of them, including LabVIEW and
>> Prograph CPX (which latter was pretty awesome actually).
>
> You mean graphical languages? I’m not sure how well they scale. Also there’s
> the problem that standard source manipulations like diff/patch and merge are
> lacking.
Plenty of others have textual source. Oz for example.
Also, I'm not sure what you mean by "scale" in this context.
>> And one can argue that stitching together UNIX tools with tees and pipes
>> and redirects is a form of dataflow.
>
> That can express fan-out, but I don’t think it can express subsequent fan-in
> from that fan-out.
In many cases you could do it in a shell but you'd have to get quite
creative. I'm not claiming in any case that UNIX system and shell offers
a full, high-powered dataflow environment.
> The standard solution to this is to introduce names for the connections
> somewhere. Which basically brings us right back to functional programming.
The "names" are single-assignment (logic) dataflow variables, that are
either unbound or bound. Computations express their dependency on
inputs; specifying the connections is a matter of indicating that
certain inputs are outputs of another computation.
It's not so much that _this_ is functional programming, but more that
many functional programming languages allow you to program in such a way
that it resembles dataflow.
AHS
--
That's not the recollection that I recall...All this information is
certainly in the hands of the auditor and we certainly await his report
to indicate what he deems has occurred.
-- Halifax, Nova Scotia mayor Peter Kelly, who is currently deeply in
the shit
|
|
0
|
|
|
|
Reply
|
Arved
|
3/26/2011 12:04:01 PM
|
|
On 26 Mrz., 05:43, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:
> On Fri, 25 Mar 2011 07:51:34 -0400, Lew <no...@lewscanon.com> wrote,
> quoted or indirectly quoted someone who said :
>
> >Good thing Java allows you to return multiple outputs by putting them into a
> >holder type, then.
>
> You could implement a language with a single input too.
Languages which can use single input and output exist
already. The Unix pipes are an example of such a logic:
cat file | sort | uniq | more
Another example comes from OO. Applying a method to the
result of another method. E.g.:
aVariable = anObject.method1().method2().method3();
Even non OO languages can support this:
aVariable := func4(func3(func2(func1(aValue))));
I see no reason to implement a new language to support
single input and output for functions.
Greetings Thomas Mertes
--
Seed7 Homepage: http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.
|
|
0
|
|
|
|
Reply
|
tm
|
3/26/2011 12:42:59 PM
|
|
On 03/26/2011 08:42 AM, tm wrote:
> Languages which can use single input and output exist
> already. The Unix pipes are an example of such a logic:
So's Java. So's C. So's Prolog, for suitable understandings of "input" and
"output".
> cat file | sort | uniq | more
>
> Another example comes from OO. Applying a method to the
Such as Java, or C#.
> result of another method. E.g.:
>
> aVariable = anObject.method1().method2().method3();
>
> Even non OO languages can support this:
>
> aVariable := func4(func3(func2(func1(aValue))));
Such as Fortran or COBOL.
> I see no reason to implement a new language to support
> single input and output for functions.
Since every computer language already supports the feature, and few restrict
you to it, your conclusion is demonstrably valid.
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
|
|
0
|
|
|
|
Reply
|
Lew
|
3/26/2011 12:51:03 PM
|
|
On 3/25/2011 9:43 PM, Roedy Green wrote:
> On Fri, 25 Mar 2011 07:51:34 -0400, Lew<noone@lewscanon.com> wrote,
> quoted or indirectly quoted someone who said :
>
>> Good thing Java allows you to return multiple outputs by putting them into a
>> holder type, then.
>
> You could implement a language with a single input too.
This is a point. Java already has such a "single input" construct, the
var-args:
void method( SomeType ... va ) { ...
I wonder if this pattern could be adapted to return types as well?
> You must
> construct an artificial (that has no meaning other than holder for
> some function) object if you need more than one parameter. Gaak! you
> say. How inconvenient! That's how I feel about requiring dummy holder
> objects for multiple outputs.
Let's see, you'd have to declare a "var-args return type:"
SomeType ... method( X x ) { ...
To use this, you might return an array directly:
SomeType ... method( X x ) {
SomeType[] st;
...
return st;
}
Or you might return a list of objects, and let the compile box them up
in to an array:
SomeType ... method( X x ) {
SomeType a, b, c, d;
...
return a, b, d;
}
To call this method, you'd either assign the result to the exact return
type (an array).
SomeType[] st = method(x);
Or you could have the compiler unbox the values for you. Unused values
are tossed away, and values which don't exist are null.
SomeType u, v, w, y;
u, v, w, y = method(x); // y will be null in this example
The only disadvantage that I can see would be folks who want to return
different type values would be tempted declare a return type of Object
var-args, which would remove a lot of the benefit of strong typing in Java.
Object ... method( Y y ); // ick!
Optimization (e.g., return values stored to the stack instead of an
explicit array) are left up to the compiler.
|
|
0
|
|
|
|
Reply
|
markspace
|
3/26/2011 4:01:38 PM
|
|
Eric Sosman <esosman@ieee-dot-org.invalid> writes:
>FWIW, at least one dialect of Lisp supports multi-valued
>expressions. You can write the moral equivalent of
>x = f(a,b,c)
>if you only care about the "principal" returned value, or the
>moral equivalent of
>(x,y) = f(a,b,c)
>if you want the ancillary value(s) as well.
It's called �Perl�:
#!/usr/bin/perl
#perl 5.8.3
use strict;
use warnings;
sub f(){ return wantarray ?( 1, 2 ): 3; }
my( $a, $b )= f();
my $c = f();
print "$a, $b\n$c\n";
1, 2
3
|
|
0
|
|
|
|
Reply
|
ram
|
3/26/2011 7:15:17 PM
|
|
Leif Roar Moldskred <leifm@dimnakorr.com> writes:
>And there's the right way (yes, my biases are showing, I know):
>procedure Example
> (A : in Float;
> B : in out Float;
> C : out Float)
Mmh, this reminds me of Ada.
Here is the entry from my personal FAQ about �multiple-return
values� in Java:
�You can't return more than one value from a method.
If you want to, you have to return a little array (unless
one value is an int and the other is a Person!) or an object
of some special little class made just for this purpose.
When I was helping Bill Joy and Guy L. Steele Jr. by
reviewing drafts of the original Java Language
Specification, I was originally upset that there was no
way to do this. So I set out to find a small example
program that obviously demanded such a feature, to
convince them that multiple value returns must be added.
I was unable to come up with one, and I could see that
Java's philosphy was to leave out things that are rarely
used and not crucial, so finally didn't say anything.�
Dan Weinreb's Weblog
http://dlweinreb.wordpress.com/category/java/
I have written several programs myself to show how multiple
returns might be emulated in Java. Each approach has its
advantages and disadvantages. I might add that, whenever I
want to achieve something with Java, the lack of explicit
multiple return values is not a problem for me.
I assume a simple multiple-return task such as, in pseudocode:
operation "sumdiff"
in x, y;
out sum, difference;
{ sum = x + y; difference = x - y; }
Solution with public fields:
class Sumdiff
{ public Sumdiff( final int x, final int y )
{ this.sum = x + y; this.difference = x - y; }
public final int sum; public final int difference; }
public class Main
{ public static void main( final java.lang.String[] args )
{ final Sumdiff result = new Sumdiff( 4, 2 );
java.lang.System.out.println
( result.sum + ", " + result.difference ); }}
6, 2
If you do not like public fields, you might use getters
as well.
A �processor object� can be created once and be used
several times:
public class Main
{ public static void main( final java.lang.String[] args )
{ final Processor processor = new Processor();
processor.set( 4, 2 );
processor.calculateSumDiff();
java.lang.System.out.println( processor.getSum() );
java.lang.System.out.println( processor.getDifference() );
processor.set( 8, 4 );
processor.calculateSumDiff();
java.lang.System.out.println( processor.getSum() );
java.lang.System.out.println( processor.getDifference() ); }}
class Processor
{ public void set( final int x, final int y )
{ this.x = x; this.y = y; }
public void calculateSumDiff()
{ this.sum = x + y; this.difference = x - y; }
public java.lang.Integer getSum(){ return sum; }
public java.lang.Integer getDifference(){ return difference; }
int x; int y; int sum; int difference; }
To avoid allocation overhead of a result object,
the client might provide and reuse such an object:
class Result { public int x; public int y; }
class Server
{ void run( final Result result, final int x, final int y )
{ result.x = x + y; result.y = x - y; }}
public final class Main
{ private static Result result = new Result(); /* single allocation */
public static void main( final java.lang.String argv[] )
{ Server server = new Server();
server.run( result, 1, 2 );
java.lang.System.out.println( result.x );
java.lang.System.out.println( result.y );
server.run( result, 3, 4 );
java.lang.System.out.println( result.x );
java.lang.System.out.println( result.y ); }}
One can also emulate multiple returns via multiple
arguments, but only when adopting a �continuation passing
style�. In the next example, the server �returns� a pair
of random numbers to the client, by calling back a method
provided by the client.
interface Client { void continuation( int x, int y ); }
class Server
{ static java.util.Random rand = new java.util.Random();
static void getPair( final Client client )
{ client.continuation( rand.nextInt( 11 ), rand.nextInt( 21 )); }}
class Example implements Client
{ public void continuation( final int x, final int y )
{ java.lang.System.out.println( x + ", " + y ); }
public void main()
{ Server.getPair( this ); }}
public class Main
{ public static void main( final java.lang.String[] args )
{ new Example().main(); }}
But, as said, I rarely ever (actually: never) have needed any
of these multiple return value emulations in my own projects.
Possibly this is because I already have accounted for the
properties and limitations of Java when I was designing
my classes. So I have designed them from the start in such
a way that multiple return values are not needed.
|
|
0
|
|
|
|
Reply
|
ram
|
3/26/2011 7:28:53 PM
|
|
Joshua Cranmer <Pidgeot18@verizon.invalid> writes:
>But mathematical functions return only one value;
In mathematics, there is no clear-drawn distinction between
�one value� and �multiple values�. For example, one
says that f, defined as f(x,y):=x+y, is a function of
�two arguments�, yet one usually gives �f: R � R -> R�,
which literally means: it is a function of /one/ argument,
which happens to be a pair. And of course, one can have
functions ... -> R x R.
|
|
0
|
|
|
|
Reply
|
ram
|
3/26/2011 7:43:02 PM
|
|
On 03/26/2011 03:43 PM, Stefan Ram wrote:
> Joshua Cranmer<Pidgeot18@verizon.invalid> writes:
>> But mathematical functions return only one value;
>
> In mathematics, there is no clear-drawn distinction between
> �one value� and �multiple values�. For example, one
> says that f, defined as f(x,y):=x+y, is a function of
> �two arguments�, yet one usually gives �f: R � R -> R�,
> which literally means: it is a function of /one/ argument,
> which happens to be a pair. And of course, one can have
> functions ... -> R x R.
That's what I said in the clause just after that semicolon: "if you want
more, you have to specify Cartesian products."
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
|
|
0
|
|
|
|
Reply
|
Joshua
|
3/26/2011 7:44:53 PM
|
|
Joshua Cranmer <Pidgeot18@verizon.invalid> writes:
>That's what I said in the clause just after that semicolon: "if you want
>more, you have to specify Cartesian products."
Sorry, I have overlooked this.
|
|
0
|
|
|
|
Reply
|
ram
|
3/26/2011 7:48:09 PM
|
|
In message <return-20110326202555@ram.dialup.fu-berlin.de>, Stefan Ram wrote:
> When I was helping Bill Joy and Guy L. Steele Jr. by
> reviewing drafts of the original Java Language
> Specification, I was originally upset that there was no
> way to do this. So I set out to find a small example
> program that obviously demanded such a feature, to
> convince them that multiple value returns must be added.
>
> I was unable to come up with one, and I could see that
> Java's philosphy was to leave out things that are rarely
> used and not crucial, so finally didn't say anything.«
Funny, I can think of any number of examples. Such as this
<http://www.codecodex.com/wiki/Reading_time_zone_files>:
(sig, ver, tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt, tzh_timecnt, tzh_typecnt, tzh_charcnt) = \
structread(zonefile, ">4s1B15x6I")
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/27/2011 12:53:04 AM
|
|
On 11-03-26 09:53 PM, Lawrence D'Oliveiro wrote:
> In message <return-20110326202555@ram.dialup.fu-berlin.de>, Stefan Ram wrote:
>
>> When I was helping Bill Joy and Guy L. Steele Jr. by
>> reviewing drafts of the original Java Language
>> Specification, I was originally upset that there was no
>> way to do this. So I set out to find a small example
>> program that obviously demanded such a feature, to
>> convince them that multiple value returns must be added.
>>
>> I was unable to come up with one, and I could see that
>> Java's philosphy was to leave out things that are rarely
>> used and not crucial, so finally didn't say anything.«
>
> Funny, I can think of any number of examples. Such as this
> <http://www.codecodex.com/wiki/Reading_time_zone_files>:
>
> (sig, ver, tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt, tzh_timecnt, tzh_typecnt, tzh_charcnt) = \
> structread(zonefile, ">4s1B15x6I")
>
That's not a compelling example. Those return values belong together,
and you're gaining nothing from breaking them out into a tuple as
opposed to having them be fields of an object. Which was rather the
point of Stefan's post.
This example of yours is no better than one where you might return a
tuple for the two coordinates of a point. As if those are truly
independent multiple return values.
AHS
--
That's not the recollection that I recall...All this information is
certainly in the hands of the auditor and we certainly await his report
to indicate what he deems has occurred.
-- Halifax, Nova Scotia mayor Peter Kelly, who is currently deeply in
the shit
|
|
0
|
|
|
|
Reply
|
Arved
|
3/27/2011 1:28:38 AM
|
|
In message <5pwjp.2224$9j5.1777@newsfe04.iad>, Arved Sandstrom wrote:
> On 11-03-26 09:53 PM, Lawrence D'Oliveiro wrote:
>> In message <return-20110326202555@ram.dialup.fu-berlin.de>, Stefan Ram
>> wrote:
>>
>>> When I was helping Bill Joy and Guy L. Steele Jr. by
>>> reviewing drafts of the original Java Language
>>> Specification, I was originally upset that there was no
>>> way to do this. So I set out to find a small example
>>> program that obviously demanded such a feature, to
>>> convince them that multiple value returns must be added.
>>>
>>> I was unable to come up with one, and I could see that
>>> Java's philosphy was to leave out things that are rarely
>>> used and not crucial, so finally didn't say anything.«
>>
>> Funny, I can think of any number of examples. Such as this
>> <http://www.codecodex.com/wiki/Reading_time_zone_files>:
>>
>> (sig, ver, tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt, tzh_timecnt, tzh_typecnt, tzh_charcnt) = \
>> structread(zonefile, ">4s1B15x6I")
>>
> That's not a compelling example. Those return values belong together,
> and you're gaining nothing from breaking them out into a tuple ...
Yes you are. Look at the rest of the code.
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/27/2011 3:08:49 AM
|
|
On 11-03-27 12:08 AM, Lawrence D'Oliveiro wrote:
> In message <5pwjp.2224$9j5.1777@newsfe04.iad>, Arved Sandstrom wrote:
>
>> On 11-03-26 09:53 PM, Lawrence D'Oliveiro wrote:
>>> In message <return-20110326202555@ram.dialup.fu-berlin.de>, Stefan Ram
>>> wrote:
>>>
>>>> When I was helping Bill Joy and Guy L. Steele Jr. by
>>>> reviewing drafts of the original Java Language
>>>> Specification, I was originally upset that there was no
>>>> way to do this. So I set out to find a small example
>>>> program that obviously demanded such a feature, to
>>>> convince them that multiple value returns must be added.
>>>>
>>>> I was unable to come up with one, and I could see that
>>>> Java's philosphy was to leave out things that are rarely
>>>> used and not crucial, so finally didn't say anything.«
>>>
>>> Funny, I can think of any number of examples. Such as this
>>> <http://www.codecodex.com/wiki/Reading_time_zone_files>:
>>>
>>> (sig, ver, tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt, tzh_timecnt, tzh_typecnt, tzh_charcnt) = \
>>> structread(zonefile, ">4s1B15x6I")
>>>
>> That's not a compelling example. Those return values belong together,
>> and you're gaining nothing from breaking them out into a tuple ...
>
> Yes you are. Look at the rest of the code.
I saw the rest of the code. Given that each of those return values is
called within 10 statements of where they were created, and only used
once or twice, and this is a one-off, the marginal convenience of using
the tuple isn't outweighed by the fragmentation it causes. This is
probably why you think it's OK.
For more maintainable code - in any language that supports it - you'd be
better off initializing an object with the zonefile information and
returning the specific information with methods or properties. Even a
named tuple would be better.
AHS
--
That's not the recollection that I recall...All this information is
certainly in the hands of the auditor and we certainly await his report
to indicate what he deems has occurred.
-- Halifax, Nova Scotia mayor Peter Kelly, who is currently deeply in
the shit
|
|
0
|
|
|
|
Reply
|
Arved
|
3/27/2011 4:05:38 AM
|
|
In message <gIyjp.4685$sj5.4444@newsfe09.iad>, Arved Sandstrom wrote:
> I saw the rest of the code. Given that each of those return values is
> called within 10 statements of where they were created, and only used
> once or twice, and this is a one-off, the marginal convenience of using
> the tuple isn't outweighed by the fragmentation it causes.
What is this “fragmentation” of which you speak?
“The concert was like the First World War. Sure we had heavy metal then, but
we called it shrapnel in those days.”
-- Alexei Sayle
> For more maintainable code - in any language that supports it - you'd be
> better off initializing an object with the zonefile information and
> returning the specific information with methods or properties.
In case you didn’t notice, that code WAS for the construction of such an
object.
|
|
0
|
|
|
|
Reply
|
Lawrence
|
3/27/2011 6:10:57 AM
|
|
On 25/03/2011 10:44 PM, Lawrence D'Oliveiro wrote:
> In message<imi0cq$ah4$1@dont-email.me>, Eric Sosman wrote:
>> You'd want something that could attach names to the pieces of the
>> assignment target, and match them up with names in the expression value.
>> Something like
>> int r, g, b;
>> (r.red, g.green, b.blue) = backgroundColor; // drop alpha
>
> In Python you can write
> r, g, b = (getattr(backgroundColor, f) for f in ("red", "green", "blue"))
> But really, is it such a big deal? In conventional languages like C we
> happily write
>
> q = y / z;
> r = y % z;
>
> and leave it to the compiler to do the dataflow analysis for us.
Quotient and remainder of division are a very special case. The hardware
sometimes has a single operation that produces both, and knowledge that
/ and % are closely related operations is built into the language. With
first = longComplexOperation(lots of arguments)
second = anotherLongComplexOperation(same set of arguments)
it's going to take a very sophisticated compiler to synthesize
(first, second) = combinedLongOperation(same set of arguments)
and it's going to have to solve the Halting Problem, too.
We already write "combined operations" in other contexts.
if (x.hasKey(y)) then x.addPair(y,
someVeryBigThingIDidn'tWantToSysnthesizeUnlessIHadTo)
sometimes gets implemented as
whereToInsert = x.findLocation(y);
if (whereToInsert.keyIsntAlreadyThere())
whereToInsert.addPair(y,...)
Or possibly whereToInsert is internal state in x and x.addPair(y,z) is
x.addAtSpotDeterminedByLastHasKey(z).
|
|
0
|
|
|
|
Reply
|
dalamb (181)
|
3/30/2011 8:10:48 PM
|
|
On 26/03/2011 3:43 PM, Stefan Ram wrote:
> Joshua Cranmer<Pidgeot18@verizon.invalid> writes:
>> But mathematical functions return only one value;
>
> In mathematics, there is no clear-drawn distinction between
> �one value� and �multiple values�. For example, one
> says that f, defined as f(x,y):=x+y, is a function of
> �two arguments�, yet one usually gives �f: R � R -> R�,
> which literally means: it is a function of /one/ argument,
> which happens to be a pair. And of course, one can have
> functions ... -> R x R.
>
And out of left field comes currying and/or closures:
g: x -> (y -> z)
where (f(x))(y) = g(x,y). But it's sometimes annoying that leaving
unbound the "second argument" of what you though of as a 2-argument
function is privileged over leaving the 1st argument unbound.
|
|
0
|
|
|
|
Reply
|
dalamb (181)
|
3/30/2011 8:15:26 PM
|
|
On 26/03/2011 12:50 AM, Roedy Green wrote:
> On Fri, 25 Mar 2011 09:43:56 -0700, markspace<-@.> wrote, quoted or
> indirectly quoted someone who said :
>
>> I think it would elucidate your refactoring pattern more if you included
>> an example. What you did post is very general:
>
> You can see the new code at
> http://mindprod.com/applet/canadiantax.html
>
> The class in question is CalculateCanadianTaxes
>
> The outputs include GST, HST, PST tax rates, GST, HST, PST tax
> amounts, total tax, and total payable.
GHAH. Conceptually that's really
CalculateCanadianTaxes: farTooManyInputs -> farTooManyOutputs
Single, vastly complex input; single, vastly complex output. I'm
serious; I can't see how anyone can think of the results of a tax
computation as anything other than one big record type.
Much nicer is the Ohio state tax form from around 1975:
OhioTax = federalTax * factorLessThanOne
But that's a whole other issue.
|
|
0
|
|
|
|
Reply
|
dalamb (181)
|
3/30/2011 8:21:01 PM
|
|
On 30/03/2011 4:10 PM, David Lamb wrote:
> first = longComplexOperation(lots of arguments)
> second = anotherLongComplexOperation(same set of arguments)
> it's going to take a very sophisticated compiler to synthesize
> (first, second) = combinedLongOperation(same set of arguments)
> and it's going to have to solve the Halting Problem, too.
I forgot to mention, the two sets of arguments might each be overlapping
subsets of a larger set of arguments, making the commonality even harder
to detect automatically. The designer really has to write
combinedLongOperation(LikelyOneObjectWithFields) that returns
AllTheResults object.
|
|
0
|
|
|
|
Reply
|
dalamb (181)
|
3/30/2011 8:25:13 PM
|
|
On 03/30/2011 04:10 PM, David Lamb wrote:
> We already write "combined operations" in other contexts.
> if (x.hasKey(y)) then x.addPair(y,
> someVeryBigThingIDidn'tWantToSysnthesizeUnlessIHadTo)
Well, another way to implement this is:
public boolean hasKey(Y y) {
LocPtr ptr = getWhereToInsert(y);
this.cachedPtr = ptr;
return ptr.valid();
}
public void addPair(Y y, Object obj) {
LocPtr ptr;
if (cachedPtr && cachedPtr.y == y)
ptr = cachedPtr;
else
ptr = getWhereToInsert(y);
ptr.insert(obj);
}
Which pretty much gets you the "benefit" of combining them into one
single operation without needing to provide all of the back-level
predicate code operations (set-if-present, set-if-not-present, etc.)
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
|
|
0
|
|
|
|
Reply
|
Pidgeot18 (1393)
|
3/30/2011 9:31:53 PM
|
|
On 3/30/2011 2:31 PM, Joshua Cranmer wrote:
> if (cachedPtr && cachedPtr.y == y)
> Which pretty much gets you the "benefit" of combining them into one
> single operation without needing to provide all of the back-level
> predicate code operations (set-if-present, set-if-not-present, etc.)
Generally, this idea seems similar to techniques used in dynamic
programming, which is itself a very powerful paradigm. Useful to know
about, at least.
http://en.wikipedia.org/wiki/Dynamic_programming
|
|
0
|
|
|
|
Reply
|
markspace
|
3/30/2011 10:52:54 PM
|
|
Joshua Cranmer wrote:
> Well, another way to implement this is:
>
> public boolean hasKey(Y y) {
> LocPtr ptr = getWhereToInsert(y);
> this.cachedPtr = ptr;
> return ptr.valid();
> }
>
> public void addPair(Y y, Object obj) {
> LocPtr ptr;
> if (cachedPtr && cachedPtr.y == y)
Umm, that won't compile in Java.
> ptr = cachedPtr;
> else
> ptr = getWhereToInsert(y);
> ptr.insert(obj);
> }
>
> Which pretty much gets you the "benefit" of combining them into one single
> operation without needing to provide all of the back-level predicate code
> operations (set-if-present, set-if-not-present, etc.)
Unless you're in multi-threaded land. In that case, don't think tacking
'synchronized' onto your method definitions will help.
--
Lew
|
|
0
|
|
|
|
Reply
|
noone7 (3512)
|
3/31/2011 3:58:02 AM
|
|
In message <RCkjp.2728$%f5.828@newsfe08.iad>, Arved Sandstrom wrote:
> On 11-03-25 11:39 PM, Lawrence D'Oliveiro wrote:
>
>> In message <Vv7jp.1732$in3.386@newsfe17.iad>, Arved Sandstrom wrote:
>>
>>> If you want to do dataflow then the best way to do it is using a
>>> dataflow language. I've used a few of them, including LabVIEW and
>>> Prograph CPX (which latter was pretty awesome actually).
>>
>> You mean graphical languages? I’m not sure how well they scale. Also
>> there’s the problem that standard source manipulations like diff/patch
>> and merge are lacking.
>
> Plenty of others have textual source. Oz for example.
So what does the language processor operate on: the graphical presentation,
or the underlying source?
> Also, I'm not sure what you mean by "scale" in this context.
As in “deal with very complex programs”.
>>> And one can argue that stitching together UNIX tools with tees and pipes
>>> and redirects is a form of dataflow.
>>
>> That can express fan-out, but I don’t think it can express subsequent
>> fan-in from that fan-out.
>
> In many cases you could do it in a shell but you'd have to get quite
> creative. I'm not claiming in any case that UNIX system and shell offers
> a full, high-powered dataflow environment.
There is always the option of bringing in named pipes (mkfifo or mknod p) to
tie disparate ends together.
>> The standard solution to this is to introduce names for the connections
>> somewhere. Which basically brings us right back to functional
>> programming.
>
> The "names" are single-assignment (logic) dataflow variables, that are
> either unbound or bound. Computations express their dependency on
> inputs; specifying the connections is a matter of indicating that
> certain inputs are outputs of another computation.
>
> It's not so much that _this_ is functional programming, but more that
> many functional programming languages allow you to program in such a way
> that it resembles dataflow.
Seems like every attempt at dataflow has to resort to using names as an
alternative to topology at some point.
|
|
0
|
|
|
|
Reply
|
ldo (2144)
|
3/31/2011 5:50:17 AM
|
|
On 11-03-31 02:50 AM, Lawrence D'Oliveiro wrote:
> In message <RCkjp.2728$%f5.828@newsfe08.iad>, Arved Sandstrom wrote:
>
>> On 11-03-25 11:39 PM, Lawrence D'Oliveiro wrote:
>>
>>> In message <Vv7jp.1732$in3.386@newsfe17.iad>, Arved Sandstrom wrote:
>>>
>>>> If you want to do dataflow then the best way to do it is using a
>>>> dataflow language. I've used a few of them, including LabVIEW and
>>>> Prograph CPX (which latter was pretty awesome actually).
>>>
>>> You mean graphical languages? I’m not sure how well they scale. Also
>>> there’s the problem that standard source manipulations like diff/patch
>>> and merge are lacking.
>>
>> Plenty of others have textual source. Oz for example.
>
> So what does the language processor operate on: the graphical presentation,
> or the underlying source?
AFAIK the graphics are just graphics; I can't speak for every graphical
language out there. LabVIEW has used a compiler since version 2.0
(version 1.0 was an interpreter on Motorola 68000). Prograph started out
in its earliest incarnations written in Prolog but moved to C early on -
I wrote new Prograph primitives for the hell of it, for matrix
operations, in C back around 20 years ago.
Generally speaking the primitives in such a graphical language are going
to be compiled bits in a library, and the program is a description of
how they stitch together, as well as storage of the layout information.
Also typically there is no underlying source - what you see *is* the source.
When I said "plenty of others" I meant _non-graphical_ dataflow
languages, incidentally. Like Oz.
>> Also, I'm not sure what you mean by "scale" in this context.
>
> As in “deal with very complex programs”.
You're not going to have worse problems with a dataflow language than
any other. It depends on the problem. Odds are you'll do better at
managing complexity with dataflow then you will with a general purpose
OOP language, for the multitude of problems that lend themselves to
dataflow.
[ SNIP ]
AHS
--
That's not the recollection that I recall...All this information is
certainly in the hands of the auditor and we certainly await his report
to indicate what he deems has occurred.
-- Halifax, Nova Scotia mayor Peter Kelly, who is currently deeply in
the shit
|
|
0
|
|
|
|
Reply
|
asandstrom3minus1 (421)
|
3/31/2011 11:51:14 PM
|
|
|
43 Replies
139 Views
(page loaded in 0.365 seconds)
|