Refactoring discovery

S

Stefan Ram

Joshua Cranmer said:
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.
 
J

Joshua Cranmer

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

Stefan Ram

Joshua Cranmer said:
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.
 
L

Lawrence D'Oliveiro

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")
 
A

Arved Sandstrom

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
 
L

Lawrence D'Oliveiro

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

Arved Sandstrom

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
 
L

Lawrence D'Oliveiro

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

David Lamb

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

David Lamb

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

David Lamb

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

David Lamb

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

Joshua Cranmer

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

markspace

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
 
L

Lew

Joshua said:
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.
 
L

Lawrence D'Oliveiro

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â€.
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 "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.
 
A

Arved Sandstrom

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

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top