Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Cleaning code

0 views
Skip to first unread message

Richard Harter

unread,
Jul 18, 2008, 3:38:56 PM7/18/08
to
On Thu, 17 Jul 2008 11:57:34 -0400, "S James S Stapleton"
<staple...@osu.edu> wrote:

>There's a programming construct I've thought of, and I've been searching on
>for it for a while, and haven't found any ideas on why it has/hasn't been
>implemented in any language.
>
>It's fairly obvious, so I'm sure there's a reason, could someone point me in
>the right direction?
>
>
>The construct: NIF
>Rationale: Numerical IF, used for comparisons. Many functions, such as
>strcmp in C, as an example, have negative values for less than, 0 for
>greater than, and 1 for equal. Three options, however, you can either use
>two options with an if (if/else), or have many options for a switch - all
>which must match exactly.
>The Format:
> A NIF statement will have a NIF statement (similar to an 'if' statement,
>such as "if(/*...*/)" in C)
> The NIF statement will have /two/ parameters FIRST and SECOND, both
>evaluate to a real numeric value (sorry, I suspect imaginary numbers would
>make this a headache).
> There would be one to three following blocks of code, EQ, LT, and GT.
> EQ need not be explicitly specified if it follows the NIF statement. It
>is executed if FIRST and SECOND are equal
> LT must be explicitly specified with it's block. It is executed if FIRST
>is less than SECOND.
> GT must be explicitly specified with it's block. It is executed if FIRST
>is greater than SECOND.

This is sort of interesting, to me anyway, but I perceive it as a
language design issue. Accordingly, I've added comp.lang.misc to
the newsgroups.

As a side note, your formatting style is bad. If the post were
any longer I wouldn't have bothered to read it.

A natural reaction for old-timers is, "Oh look, he's reinventing
the fortran arithmetic if." This is unfortunate and a bit
unfair, because you're not. The old fortran arithmetic if looked
like this:

if (x) 100,200,300
100 <sequence of statements>
200 <sequence of statements>
300 <sequence of statements>

The original fortran language had no notion of blocks so one had
to manufacture them by hand. It also didn't have any notion of a
caseof/switch/select construct. Furthermore it was a test on a
number rather than a test on the result of a comparison. The
only real resemblence is the use of a ternary comparison.

As pseudocode your proposal in a modern language would look
something like this:

select_compare(x,y)
LT: <code for the less than block>
EQ: <code for the equal block>
GT: <code for the greater than block>
end select_compare

You can manufacture something like this in C for numbers by
creating a macro that compares two numbers and returns -1,0,1 as
the case may be. I opine that it would be a horrible idea. Then
again, I sometimes think that using C is a horrible idea.

Instead of marching boldly into the past, I propose to speculate
a bit. First of all, there is no need for the compared arguments
to be numbers. They could any kind of type that is an order
type, i.e., any type that has a defined order relationship.

Then there is the question of what the comparison yields. In C
strcmp yields -1, 0, and 1. However this is a hack. Decent
languages have a native boolean type with values true and false;
one could consider having a native three valued type with values
lt, eq, and gt.

No doubt the babykillers will dismiss the idea out of hand. (A
babykiller is someone who dismisses any novel idea out of hand
because it is a baby, i.e., it doesn't have a known, familiar
track record; being a babykiller saves an immense amount of
thought.) Be that as it may, having ordering values as a type
would make for cleaner code. As a language feature the
implementation would be cheap and easy, although it could be
difficult to shoehorn into existing languages.

What might be interesting would be the capability of manipulating
order relationship statements in much the same that one can
manipulate boolean relationships. There is probably a whole body
of theory out there that I don't know anything about. As an
example, consider triplets of the form (x,y,v) where v is the
order relationship between x and y. Then if we have two triplets
(x,y,u) and (y,z,v) and we know that u=v then we also know that
(x,z,v).

Richard Harter, c...@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.

S James S Stapleton

unread,
Jul 18, 2008, 3:46:13 PM7/18/08
to

> What might be interesting would be the capability of manipulating
> order relationship statements in much the same that one can
> manipulate boolean relationships. There is probably a whole body
> of theory out there that I don't know anything about. As an
> example, consider triplets of the form (x,y,v) where v is the
> order relationship between x and y. Then if we have two triplets
> (x,y,u) and (y,z,v) and we know that u=v then we also know that
> (x,z,v).

You got my idea fairly well I think. Your psudocode was definitely better
than mine.

I've been considering trying to add this idea to python. I like your concept
of an ordering type.

Thanks for the input,
-Jim Stapleton


Bart

unread,
Jul 18, 2008, 7:27:39 PM7/18/08
to
On Jul 18, 8:38 pm, c...@tiac.net (Richard Harter) wrote:
> On Thu, 17 Jul 2008 11:57:34 -0400, "S James S Stapleton"
> <stapleton...@osu.edu> wrote:
> >There's a programming construct I've thought of, and I've been searching on
> >for it for a while, and haven't found any ideas on why it has/hasn't been
> >implemented in any language.

> Then there is the question of what the comparison yields.  In C


> strcmp yields -1, 0, and 1. However this is a hack.  Decent
> languages have a native boolean type with values true and false;
> one could consider having a native three valued type with values
> lt, eq, and gt.

You're forgetting le and ge, which would be easier to deal with using
-1,0,1.

There's also ne, but I'm not sure how that would fit in. Perhaps a
relative compare should return the 3-element set [lt, eq, gt]. Then le
is [lt,eq], ge is [eq,gt]. 'ne' is best expressed as not [eq].


--
Bartc

Ben Bacarisse

unread,
Jul 18, 2008, 7:45:23 PM7/18/08
to
c...@tiac.net (Richard Harter) writes:

> This is sort of interesting, to me anyway, but I perceive it as a
> language design issue. Accordingly, I've added comp.lang.misc to
> the newsgroups.

<snip>
> ... Decent


> languages have a native boolean type with values true and false;
> one could consider having a native three valued type with values
> lt, eq, and gt.

Or LT, GT and EQ in Haskell. I don't see why the type needs to be
native unless, by that, you mean that any built-in types must have an
operator that produces the correct values.

The Haskell's type classes (in particular Eq and Ord) are, in my
opinion, an object lesson in how to design equality and ordering in a
programming language. If you are interested in this area you must at
least see how it is done there.

--
Ben.

Reinder Verlinde

unread,
Jul 18, 2008, 8:13:54 PM7/18/08
to
In article
<5e9bb46e-dfdb-4872...@i76g2000hsf.googlegroups.com>,
Bart <b...@freeuk.com> wrote:

> On Jul 18, 8:38 pm, c...@tiac.net (Richard Harter) wrote:
> > On Thu, 17 Jul 2008 11:57:34 -0400, "S James S Stapleton"
> > <stapleton...@osu.edu> wrote:
> > >There's a programming construct I've thought of, and I've been searching on
> > >for it for a while, and haven't found any ideas on why it has/hasn't been
> > >implemented in any language.
>
> > Then there is the question of what the comparison yields.  In C
> > strcmp yields -1, 0, and 1. However this is a hack.  Decent
> > languages have a native boolean type with values true and false;
> > one could consider having a native three valued type with values
> > lt, eq, and gt.
>
> You're forgetting le and ge, which would be easier to deal with using
> -1,0,1.

For IEEE floating point, you also may be forgetting "not comparable"
and, possibly "sort-of-equal" (for comparison of +0.0 with -0.0)

Users doing interval arithmetic or using a 'stochast' type might want
even more variants (for example a return value indicating the
probability that stochast 1 is less than stochast 2)

Because of these, I do not think a programming language can decide on
the best set of these. I would go for a good type system and a good
'case/switch' variant. Those would allow library writers to choose the
variant(s) they need.

The standard library, then, might decide to provide a simple LT,EQ,GT
type.

Reinder

Rod Pemberton

unread,
Jul 19, 2008, 4:14:11 AM7/19/08
to
"Richard Harter" <c...@tiac.net> wrote in message
news:4880bd90...@news.sbtc.net...
(picking up conversation from c.l.m, i.e., perhaps lost context...)

No offense - I'm curious, but I don't see what value this offers. With a
function like strcmp(), you wan't either a true/false result or you want a
specific one out of three result. I.e., are they equal or not? Or, how are
they different? It is "nifty" that they combined two methods of comparison
into a single function. So, I don't understand why you'd need two or three
of three results. But, if you did, you just save the result to a temporary
variable or "flag" and use another if() or 'else if()'... Also, compilers
optimize switch() very well. I'm also curious as to how you delimit each
block? The first block would be deliminated by nif(), the last block by
else() (yes/no?), but what keyword do you use for the middle block? Or, was
this supposed to be setup more like a switch() using 'case'? Either way,
it's not that difficult to implement a nif() with existing functionality -
likely one reason nif() doesn't exist. C basically has two versions of if()
already, a terminated if() that has no else(), and an unterminated if().
The C language would be slightly easier to parse if the terminated if() were
known in advance, say by using tif() keyword, instead of having to wait to
see if else() syntax is present. (That would make C more LALR(1) leaving
only the need for an additional keyword for typedef use.)


Rod Pemberton

Richard Harter

unread,
Jul 19, 2008, 10:40:16 AM7/19/08
to
On Fri, 18 Jul 2008 16:27:39 -0700 (PDT), Bart <b...@freeuk.com>
wrote:

>On Jul 18, 8:38=A0pm, c...@tiac.net (Richard Harter) wrote:
>> On Thu, 17 Jul 2008 11:57:34 -0400, "S James S Stapleton"
>> <stapleton...@osu.edu> wrote:

>> >There's a programming construct I've thought of, and I've been searching=
> on
>> >for it for a while, and haven't found any ideas on why it has/hasn't bee=


>n
>> >implemented in any language.
>

>> Then there is the question of what the comparison yields. =A0In C
>> strcmp yields -1, 0, and 1. However this is a hack. =A0Decent


>> languages have a native boolean type with values true and false;
>> one could consider having a native three valued type with values
>> lt, eq, and gt.
>
>You're forgetting le and ge, which would be easier to deal with using
>-1,0,1.
>
>There's also ne, but I'm not sure how that would fit in. Perhaps a
>relative compare should return the 3-element set [lt, eq, gt]. Then le
>is [lt,eq], ge is [eq,gt]. 'ne' is best expressed as not [eq].

No, the compare should return one of the three. To get le, ne,
or ge, do a boolean negation, e.g., in C, le is
!(compare(x,y)==gt).

Richard Harter

unread,
Jul 19, 2008, 10:44:17 AM7/19/08
to
On Sat, 19 Jul 2008 00:45:23 +0100, Ben Bacarisse
<ben.u...@bsb.me.uk> wrote:

>c...@tiac.net (Richard Harter) writes:
>
>> This is sort of interesting, to me anyway, but I perceive it as a
>> language design issue. Accordingly, I've added comp.lang.misc to
>> the newsgroups.
><snip>
>> ... Decent
>> languages have a native boolean type with values true and false;
>> one could consider having a native three valued type with values
>> lt, eq, and gt.
>
>Or LT, GT and EQ in Haskell. I don't see why the type needs to be
>native unless, by that, you mean that any built-in types must have an
>operator that produces the correct values.

I like Erlang's approach to case - identifiers are lower case,
atoms are upper case. It's ever so much cleaner.

I think I mean what you think I meant about native types, I
think.

>
>The Haskell's type classes (in particular Eq and Ord) are, in my
>opinion, an object lesson in how to design equality and ordering in a
>programming language. If you are interested in this area you must at
>least see how it is done there.

Thanks, I will take a look.

lawrenc...@siemens.com

unread,
Jul 19, 2008, 4:14:03 PM7/19/08
to
Richard Harter <c...@tiac.net> wrote:
>
> No, the compare should return one of the three. To get le, ne,
> or ge, do a boolean negation, e.g., in C, le is
> !(compare(x,y)==gt).

Or just use the not equal operator: compare(x,y)!=gt.
--
Larry Jones

The hardest part for us avant-garde post-modern artists is
deciding whether or not to embrace commercialism. -- Calvin

S James S Stapleton

unread,
Jul 21, 2008, 8:55:31 AM7/21/08
to
> No offense - I'm curious, but I don't see what value this offers. With a
> function like strcmp(), you wan't either a true/false result or you want a
> specific one out of three result. I.e., are they equal or not? Or, how
> are
> they different?

Exactly, how are they different is the point here. Is the first less than,
equal to or greater than the second?

In each one may have a different requirement.

The use would be in sorting and binary searches mostly. It could clean up
the code.

> It is "nifty" that they combined two methods of comparison
> into a single function. So, I don't understand why you'd need two or
> three
> of three results. But, if you did, you just save the result to a
> temporary
> variable or "flag" and use another if() or 'else if()'... Also, compilers
> optimize switch() very well.

The former is more convoluted than what I was talking about. The latter
won't necessarily work. At least in C, -1, 0, 1 behavior doesn't appear to
be guranteed it's less than 0, 0 or greater than 0 in a lot of functions.
Doing a three-case switch would probably work on most/all compilers, but to
be sure, you'd either need a 2^N case switch (N being the number of bits in
the integer type used for the return), or a 4 case switch (one default,
which would divide the value by it's absolute value, and restart the
switch - slower).

> I'm also curious as to how you delimit each
> block? The first block would be deliminated by nif(), the last block by
> else() (yes/no?), but what keyword do you use for the middle block?

no.

nif(INTEGER_EXPRESSION[, INTEGER_EXPRESSION])
[eq] {
CODE
}
[lt] {
CODE
}
[gt] {
CODE
}

eq/lt/gt can go in any order, but must be specified if not in the above
order


> Or, was
> this supposed to be setup more like a switch() using 'case'? Either way,
> it's not that difficult to implement a nif() with existing functionality -
> likely one reason nif() doesn't exist.

A switch wouldn't work, as I stated above, in many cases.

it could be set up with if's and else-if's, but then you have two issues -
you either need to potentially call a function multiple times, or create a
temporary variable - and hope it's not used:

#define nif(A, B) \
int nif_A = A; \
int nif_B = B; \
#define nif_eq \
if(nif_A == nif_B)
#define nif_lt \
else if(nif_A < nif_B)
#define nif_gt \
else

There are a lot of problems with this code - too easy to screw up the
implementation, order is restricted, you can only use it once in a block,
etc. Fixing these would require a lot more effort on the part of the
developer.


-Jim Stapleton


Rod Pemberton

unread,
Jul 21, 2008, 7:45:16 PM7/21/08
to
"S James S Stapleton" <staple...@osu.edu> wrote in message
news:g62104$l3b$1...@charm.magnus.acs.ohio-state.edu...

> The use would be in sorting and binary searches mostly. It could clean up
> the code.

Ok.

> At least in C, -1, 0, 1 behavior doesn't appear to
> be guranteed it's less than 0, 0 or greater than 0 in a lot of functions.

-1,0,1 is only returned for string functions (strcmp,strncmp). IIRC, there
are *no* other functions that do. Is there any reason extend the language
to support only two string functions?

> Doing a three-case switch would probably work on most/all compilers, but
> to be sure, you'd either need a 2^N case switch (N being the number of

> bits the integer type used for the return),

No... Or, I would avoid that.

> or a 4 case switch (one
> default, which would divide the value by it's absolute value, and restart
> the switch - slower).

Restart the switch? Why? Why not just switch on the "divide the value by
it's absolute value" in the first place? Actually, I'm not sure if the
switch() will switch on signed values (It probably does...), and I prefer
unsigned anyway, so I'd probable scale -1,0,1 to 0,1,2. E.g., like:

switch((value/abs(value))+1)
{
}

(Sorry, I don't remember the integer promotions off the top of my head, so
that may need a cast...)

>}
nif(INTEGER_EXPRESSION[, INTEGER_EXPRESSION])
> [eq] {
> CODE
> }
> [lt] {
> CODE
> }
> [gt] {
> CODE
> }
>

If we rewrite that slightly,

nif(INTEGER_EXPRESSION[, INTEGER_EXPRESSION])
{
_eq_ {
CODE
}
_lt_ {
CODE
}
_gt_ {
CODE
}
}


Then, it's C structure is very similar to a switch:

switch()
{
case 0x00:
{
}
case 0x01:
{
}
case 0x02:
{
}
}


Now, you could hide the switch behind defines:

#define nif(x) switch(((x)/abs(x))+1)
#define _eq_ case 0x00:
#define _lt_ case 0x01:
#define _gt_ case 0x02:

nif(x)
{
_eq_
{
}
_lt_
{
}
_gt_
{
}
}


If that nif() is too simple, then have it switch on an evaluation function:

int _nif_eval(int value)
{
return( /* 0,1,2 based on your logic */);
}

#define nif(x) switch(_nif_eval(x))


> eq/lt/gt can go in any order, but must be specified if not in the above
> order

When using a switch() based method, you could have all, or none, in any
order.

> it could be set up with if's and else-if's, but then you have two issues -
> you either need to potentially call a function multiple times, or create a
> temporary variable - and hope it's not used:
>
> #define nif(A, B) \
> int nif_A = A; \
> int nif_B = B; \
> #define nif_eq \
> if(nif_A == nif_B)
> #define nif_lt \
> else if(nif_A < nif_B)
> #define nif_gt \
> else

More reason for using switch(), I'd say...


Rod Pemberton

Ben Bacarisse

unread,
Jul 21, 2008, 8:55:17 PM7/21/08
to
"Rod Pemberton" <do_no...@nohavenot.cmm> writes:

> "S James S Stapleton" <staple...@osu.edu> wrote in message
> news:g62104$l3b$1...@charm.magnus.acs.ohio-state.edu...

>> At least in C, -1, 0, 1 behavior doesn't appear to
>> be guranteed it's less than 0, 0 or greater than 0 in a lot of functions.
>
> -1,0,1 is only returned for string functions (strcmp,strncmp).

It is not guaranteed by the language standard so you can't rely on it.
The comparison operators must produce 0 or 1 but the functions need
not.

<snip>


> Restart the switch? Why? Why not just switch on the "divide the value by
> it's absolute value" in the first place? Actually, I'm not sure if the
> switch() will switch on signed values (It probably does...),

It does.

> and I prefer
> unsigned anyway, so I'd probable scale -1,0,1 to 0,1,2. E.g., like:
>
> switch((value/abs(value))+1)

That goes wrong when value == 0. You could use (value>0) - (value<0)
in a switch.

--
Ben.

Rod Pemberton

unread,
Jul 21, 2008, 11:04:33 PM7/21/08
to
"Ben Bacarisse" <ben.u...@bsb.me.uk> wrote in message
news:873am23...@bsb.me.uk...

> "Rod Pemberton" <do_no...@nohavenot.cmm> writes:
>
> > "S James S Stapleton" <staple...@osu.edu> wrote in message
> > news:g62104$l3b$1...@charm.magnus.acs.ohio-state.edu...
> >> At least in C, -1, 0, 1 behavior doesn't appear to
> >> be guranteed it's less than 0, 0 or greater than 0 in a lot of
functions.
> >
> > -1,0,1 is only returned for string functions (strcmp,strncmp).
>
> It is not guaranteed by the language standard so you can't rely on it.

That statement is really unclear. What's not guaranteed? Three returns?
strcmp() and strncmp()? I'll take it you're going on about values -1 and 1.
Okay then: negative, 0, positive. The point remains: only two functions
return: negative, 0, positive, that I'm aware of. So, why does he need
nif()?

> The comparison operators must produce 0 or 1

True, at least for C99... got to find a C89 spec.

> but the functions need not [produce 0 or 1].

That statement is really unclear too. strcmp() and strncmp() are required
to return 3 values... Your statement implies two, and states one required
value isn't: 0. It's required to produce 0 when equal. It's not required
to produce 1, but a positive value. It's also required to produce a
negative value.

> > Restart the switch? Why? Why not just switch on the "divide the value
by
> > it's absolute value" in the first place? Actually, I'm not sure if the
> > switch() will switch on signed values (It probably does...),
>
> It does.

That brings up something interesting...

n1256 draft

"The switch statement" 6.8.4.2 sub 1 and 3

"The controlling expression of a switch statement shall have integer type."
"The expression of each case label shall be an integer constant
expression..."

So, the "integer type" of the switch must match an "integer constant
expression" case label.

"Constant expressions" 6.6. sub 6

"An integer constant expression99) shall have integer type and shall only
have operands that are integer constants, enumeration constants, character
constants, sizeof expressions whose results are integer constants, and
floating constants that are the immediate operands of casts."

Since we want "integer constants" as our "integer constant expression",

"Integer constants" 6.4.4.1

Odd, although 6.4.4.1 indicates they can be signed, i.e., "shall be in the
range of representable values for its type", I don't see any sign prefixes
in the grammer of "6.4.4.1 Integer constants" n1256 draft... If the sign of
an integer isn't part of the "integer constant" grammar, just how do
"integer constants" get their sign? Yeah, love the spec... not.

> > and I prefer
> > unsigned anyway, so I'd probable scale -1,0,1 to 0,1,2. E.g., like:
> >
> > switch((value/abs(value))+1)
>
> That goes wrong when value == 0. You could use (value>0) - (value<0)
> in a switch.
>

Good call. Sigh, just working off what he posted...


Rod Pemberton

Ben Bacarisse

unread,
Jul 22, 2008, 8:29:32 AM7/22/08
to
"Rod Pemberton" <do_no...@nohavenot.cmm> writes:

> "Ben Bacarisse" <ben.u...@bsb.me.uk> wrote in message
> news:873am23...@bsb.me.uk...
>> "Rod Pemberton" <do_no...@nohavenot.cmm> writes:
>>
>> > "S James S Stapleton" <staple...@osu.edu> wrote in message
>> > news:g62104$l3b$1...@charm.magnus.acs.ohio-state.edu...
>> >> At least in C, -1, 0, 1 behavior doesn't appear to
>> >> be guranteed it's less than 0, 0 or greater than 0 in a lot of
> functions.
>> >
>> > -1,0,1 is only returned for string functions (strcmp,strncmp).
>>
>> It is not guaranteed by the language standard so you can't rely on it.
>
> That statement is really unclear. What's not guaranteed? Three
> returns?

Sorry, I thought you were suggesting that strcmp and strncmp returned
one of -1, 0 or 1. I think from reading this reply that you were
using -1 and 1 as "exemplars". It is clearer to write <0, 0, >0 or
something like that.

Anyway, to be absolutely clear (for posterity) while C guarantees that
its comparison and logical operators produce either 0 or 1 (rather
than 0 and non-zero), the compare /functions/ are obliged only to
return an int that is either less that zero, equal to zero, or greater
than zero.

> strcmp() and strncmp()? I'll take it you're going on about values -1 and 1.
> Okay then: negative, 0, positive. The point remains: only two functions
> return: negative, 0, positive, that I'm aware of.

There's also strcoll, memcmp, wmemcmp, wcscmp, wcsncmp and wcscoll.

<snip>
>> > ... Why not just switch on the "divide the value by


>> > it's absolute value" in the first place? Actually, I'm not sure if the
>> > switch() will switch on signed values (It probably does...),
>>
>> It does.
>
> That brings up something interesting...
>
> n1256 draft
>
> "The switch statement" 6.8.4.2 sub 1 and 3
>
> "The controlling expression of a switch statement shall have integer type."
> "The expression of each case label shall be an integer constant
> expression..."
>
> So, the "integer type" of the switch must match an "integer constant
> expression" case label.
>
> "Constant expressions" 6.6. sub 6
>
> "An integer constant expression99) shall have integer type and shall only
> have operands that are integer constants, enumeration constants, character
> constants, sizeof expressions whose results are integer constants, and
> floating constants that are the immediate operands of casts."
>
> Since we want "integer constants" as our "integer constant expression",
>
> "Integer constants" 6.4.4.1
>
> Odd, although 6.4.4.1 indicates they can be signed, i.e., "shall be in the
> range of representable values for its type", I don't see any sign prefixes
> in the grammer of "6.4.4.1 Integer constants" n1256 draft... If the sign of
> an integer isn't part of the "integer constant" grammar, just how do
> "integer constants" get their sign? Yeah, love the spec... not.

It seems clear to me. You are permitted to have constants (like 1)
and the syntax is that of a conditional expression (i.e. all the
assignment operators and the , operator are not permitted). -1 is as
valid as 1 + 1.

--
Ben.

Rod Pemberton

unread,
Jul 22, 2008, 9:05:12 PM7/22/08
to
"Rod Pemberton" <do_no...@nohavenot.cmm> wrote in message
news:g63751$mv0$1...@aioe.org...

Oh, yeah, you'll still need some break statements too... :)


Rod Pemberton

Rod Pemberton

unread,
Jul 22, 2008, 9:06:35 PM7/22/08
to
"Rod Pemberton" <do_no...@nohavenot.cmm> wrote in message
news:g63iqo$u80$1...@aioe.org...

> > > and I prefer
> > > unsigned anyway, so I'd probable scale -1,0,1 to 0,1,2. E.g., like:
> > >
> > > switch((value/abs(value))+1)
> >
> > That goes wrong when value == 0. You could use (value>0) - (value<0)
> > in a switch.
> >
>
> Good call. Sigh, just working off what he posted...
>

Though, since a single value is needed to switch, you could use the
"conditional operator" to correct the divide by zero:

switch((value/(value?abs(value):1))+1)


So, that'd give you something like this (with breaks this time,
untested...):

#define nif(x) switch(((x)/((x)?abs(x):1))+1)


#define _eq_ case 0x00:
#define _lt_ case 0x01:
#define _gt_ case 0x02:

#define _out_ break;

nif(x)
{
_eq_
{
_out_
}
_lt_
{
_out_
}
_gt_
{
_out_
}
}


RP

Rod Pemberton

unread,
Jul 22, 2008, 9:21:59 PM7/22/08
to
"Ben Bacarisse" <ben.u...@bsb.me.uk> wrote in message
news:87y73u1...@bsb.me.uk...

> > The point remains: only two functions
> > return: negative, 0, positive, that I'm aware of.
>
> There's also strcoll, memcmp,

4...
memcmp() - Hey, that's good to know, if I ever use it...
strcoll() - Worthless...

> wmemcmp, wcscmp, wcsncmp and wcscoll.

Huh? Widechars... Why couldn't they have stopped at C89...? Didn't they
learn with C89 that "shotgun" language design didn't work? Anyone on c.l.c.
indicate that they like or even use wchar.h?


RP

thomas...@gmx.at

unread,
Jul 23, 2008, 1:42:48 PM7/23/08
to
On 18 Jul., 21:38, c...@tiac.net (Richard Harter) wrote:
> On Thu, 17 Jul 2008 11:57:34 -0400, "S James S Stapleton"
>

Since Seed7 can define new statements, it is almost a must, to show
up with a proposal. Would the following statement be okay for you:

if a cmp b is
lt: writeln(a <& " is less than " <& b);
eq: writeln(a <& " is equal to " <& b);
gt: writeln(a <& " is greater than " <& b);
end if;

The syntax of this statement can be defined with the S7SSD (Seed7
structured syntax definition):

$ syntax expr: .if.().cmp.().is.
lt. : .().
eq. : ,().
gt. : .().
end.if is -> 25;

The semantic of this statement can be defined with:

const proc: if (in integer: a) cmp (in integer: b) is
lt: (in proc: ltPart)
eq: (in proc: eqPart)
gt: (in proc: gtPart)
end if is func
begin
if a < b then
ltPart;
elsif a = b then
eqPart;
else
gtPart;
end if;
end func;

That's it. Now the numerical if statement is defined for integer's.

The template mechanism can be used to define a template for the
numerical if statement. This way it would be easy to instantiate
numerical if statements for various types (even for non-numerical
ones like char and string).

---------- Some tests follow - please ignore ----------
First Test
.

Some line which contains data
Second Test
.
.

.

.
.

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.

S James S Stapleton

unread,
Jul 23, 2008, 1:55:03 PM7/23/08
to

<thomas...@gmx.at> wrote in message
news:3cd12e36-db8c-4bb7...@y21g2000hsf.googlegroups.com...

Yeah, that looks about rigth. Interesting language concept.

-Jim Stapleton


thomas...@gmx.at

unread,
Jul 23, 2008, 3:55:34 PM7/23/08
to
On 22 Jul., 01:45, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wrote:
> "S James S Stapleton" <stapleton...@osu.edu> wrote in messagenews:g62104$l3b$1...@charm.magnus.acs.ohio-state.edu...

>
> Restart the switch?  Why?  Why not just switch on the "divide the value by
> it's absolute value" in the first place?  Actually, I'm not sure if the
> switch() will switch on signed values (It probably does...), and I prefer
> unsigned anyway, so I'd probable scale -1,0,1 to 0,1,2.  E.g., like:
>
>   switch((value/abs(value))+1)

Besides doing a division by zero for the value 0 (as pointed
out already in another mail), I think that normally a division
is a very expensive operation which should be avoided here.

---------- Some tests follow - please ignore ----------

.
..
...
....
.....
.
..
...
....
.....
.x
. x
..x
.. x
...x
... x
....x
.... x

thomas...@gmx.at

unread,
Jul 23, 2008, 5:56:16 PM7/23/08
to
On 23 Jul., 21:55, thomas.mer...@gmx.at wrote:
> Besides doing a division by zero for the value 0 (as pointed
> out already in another mail), I think that normally a division
> is a very expensive operation which should be avoided here.

I don't like to follow myself, but I got another idea:
I think that a switch (implemented with a computed goto)
is not as fast as two ifs, because it needs a check for
being in the range of the case labels. E.g.:

switch (number) {
case -1: something_a(); break;
case 0: something_b(); break;
case 1: something_c(); break;
}

The code generated for this switch statement cannot be
reduced to a computed goto. Additionally it is necessary
to check for the values < -1 and > 1, because in that
case nothing should be done. That means that at least
two comparisons take place, when a swich statement is
really implemented with a computed goto. Of cause a C
compiler will take this overhead into account and
generate conditional jumps instead of a computed goto,
when they are faster.

---------- Some tests follow - please ignore ----------

The last tests at the end of the mail failed,
therefore I need to repeat them, sorry.

.
..
...
....
.....
.
..
...
....
.....
.x
. x
..x
.. x
...x
... x
....x
.... x

.x.
.x..
..x.
..x..
.x.x
.x..x
..x.x
..x..x
x
x

thomas...@gmx.at

unread,
Jul 23, 2008, 6:05:53 PM7/23/08
to
On 23 Jul., 21:55, thomas.mer...@gmx.at wrote:

> > Besides doing a division by zero for the value 0 (as pointed
> > out already in another mail), I think that normally a division
> > is a very expensive operation which should be avoided here.

> Of cause a C compiler will take this overhead into account and


> generate conditional jumps instead of a computed goto,
> when they are faster.

I forgot to mention: At the machine level there
might be an instruction which does already this
3-way branch.

---------- Some tests follow - please ignore ----------

.

Rod Pemberton

unread,
Jul 23, 2008, 6:57:33 PM7/23/08
to
<thomas...@gmx.at> wrote in message
news:9d5f9fa4-bef9-44d9...@m45g2000hsb.googlegroups.com...

On 22 Jul., 01:45, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wrote:
> "S James S Stapleton" <stapleton...@osu.edu> wrote in
messagenews:g62104$l3b$1...@charm.magnus.acs.ohio-state.edu...
> >
> > Restart the switch? Why? Why not just switch on the "divide the value by
> > it's absolute value" in the first place? Actually, I'm not sure if the
> > switch() will switch on signed values (It probably does...), and I
prefer
> > unsigned anyway, so I'd probable scale -1,0,1 to 0,1,2. E.g., like:
> >
> > switch((value/abs(value))+1)
>
> Besides doing a division by zero for the value 0 (as pointed
> out already in another mail), I think that normally a division
> is a very expensive operation which should be avoided here.
>

Okay, then:

switch(-1*(i<0)+(i>0)) /* -1,0,1 */

Or,

switch((i==0)+2*(i>0)) /* 0,1,2 for -1,0,1 */


RP

Reinder Verlinde

unread,
Jul 23, 2008, 6:59:58 PM7/23/08
to
In article
<d5fb032c-6305-4ae7...@p25g2000hsf.googlegroups.com>,
thomas...@gmx.at wrote:

> On 23 Jul., 21:55, thomas.mer...@gmx.at wrote:
> > Besides doing a division by zero for the value 0 (as pointed
> > out already in another mail), I think that normally a division
> > is a very expensive operation which should be avoided here.
>
> I don't like to follow myself, but I got another idea:
> I think that a switch (implemented with a computed goto)
> is not as fast as two ifs, because it needs a check for
> being in the range of the case labels. E.g.:
>
> switch (number) {
> case -1: something_a(); break;
> case 0: something_b(); break;
> case 1: something_c(); break;
> }
> The code generated for this switch statement cannot be
> reduced to a computed goto. Additionally it is necessary
> to check for the values < -1 and > 1, because in that
> case nothing should be done. That means that at least
> two comparisons take place

Two? If the CPU has native support for unsigneds:

int unsigned temp = (int unsigned)(number + 1);
if( temp < 3) {
functions[temp]();
}

Also, if you design you own language, you might consider a switch
variant that has undefined behavior for values not in any 'case'.

Reinder

Curtis W

unread,
Jul 23, 2008, 8:29:35 PM7/23/08
to

It seems rather pointless implementing this in a language other than
C. Conceptually, its sole purpose is to work around a poorly-
implemented library function; or, in this case, a poorly written spec.
As far as I can tell, the problem vanishes when you limit the possible
return values to -1, 0, and 1. Once you do that, you can get by with a
simple switch statement:

switch(strcmp(x, y)) {
case -1: break;
case 0: break;
case 1: break;
}


P.S.
Ignore this post if it turns out that you just wanted to pimp your
language.

thomas...@gmx.at

unread,
Jul 24, 2008, 3:17:16 AM7/24/08
to
On 24 Jul., 00:59, Reinder Verlinde <rein...@verlinde.invalid> wrote:
> In article
> <d5fb032c-6305-4ae7-a529-3eb4442e3...@p25g2000hsf.googlegroups.com>,

>
> thomas.mer...@gmx.at wrote:
> > On 23 Jul., 21:55, thomas.mer...@gmx.at wrote:
> > > Besides doing a division by zero for the value 0 (as pointed
> > > out already in another mail), I think that normally a division
> > > is a very expensive operation which should be avoided here.
>
> > I don't like to follow myself, but I got another idea:
> > I think that a switch (implemented with a computed goto)
> > is not as fast as two ifs, because it needs a check for
> > being in the range of the case labels. E.g.:
>
> > switch (number) {
> > case -1: something_a(); break;
> > case 0: something_b(); break;
> > case 1: something_c(); break;
> > }
> > The code generated for this switch statement cannot be
> > reduced to a computed goto. Additionally it is necessary
> > to check for the values < -1 and > 1, because in that
> > case nothing should be done. That means that at least
> > two comparisons take place
>
> Two? If the CPU has native support for unsigneds:
>
> int unsigned temp = (int unsigned)(number + 1);
> if( temp < 3) {
> functions[temp]();
> }

Good point.

> Also, if you design you own language, you might consider a switch
> variant that has undefined behavior for values not in any 'case'.

I agree in principle, but the Seed7 compiler generates C instead
of machine code. Therefore I am currently limited to what can
expressed with C.

To use C as some sort of portable assembler is a practical
approach that allows me to concentrate on higher level
things instead of code generation.

The advantage of using C is that if your Seed7 program just
uses features directly supported by C you get also C's performance.

---------- Some tests follow - please ignore ----------


µ
äöüß
.
..


...
.x
. x
..x
.. x

.x.
.x..
..x.
..x..
.x.x
.x..x
..x.x
..x..x

Greetings Thomas Mertes

thomas...@gmx.at

unread,
Jul 24, 2008, 4:50:01 AM7/24/08
to

The OP wrote about a 'Numerical IF' which is a structured version of
FORTRAN's arithmetic IF statement. This has nothing to do with the
design of the 'strcmp' function which returns an integer less than,
equal to, or greater than zero instead of just -1, 0, 1 .

The OP wrote also about 'real numeric value' which probably means
'float' or 'double' instead of just 'int'. Of cause, you could
define some sort of 'fltcmp' or 'intcmp' function or macro (which
should return -1, 0, 1 for less than, equal and greater than), and
use a switch statement in the way you suggested.

What is left out are performance considerations. Will

switch (-(x < y) + (x > y)) {
case -1: do_a(); break;
case 0: do_b(); break;
case 1: do_c(); break;
}

or

if (x < y) {
do_a();
} else if (x == y) {
do_b();
} else {
do_c();
}

be faster?
A numerical IF (I would prefer the term comparison IF) statement
can be defined in one of this two ways (or in another way).


In your program you would just write:

if a cmp b is

lt: do_a;
eq: do_b;
gt: do_b;
end if;

Which means that the implementation is separated from the
use of the statement. That way you can use this statement at
various places in your program, and experiment with the
implementation of it later.

> P.S.
> Ignore this post if ...

Please don't draw conclusions from your motivations to other
peoples intentions.

There is also a general principle that silence cannot be
interpreted as agreement.

That means that statements like:
If you don't answer me, you aggree to owe me 1000000€.
cannot be enforced by legal action.

So let's assume that releasing open source software is something
positive.

---------- Some tests follow - please ignore ----------

$-1ôÌ
µ
äöüß
°§²³@
.


..
.x
. x
..x
.. x
.x.
.x..
..x.
..x..
.x.x
.x..x
..x.x
..x..x

Greetings Thomas Mertes

S James S Stapleton

unread,
Jul 24, 2008, 8:24:47 AM7/24/08
to

<thomas...@gmx.at> wrote in message
news:09e4087a-4a26-4b0a...@59g2000hsb.googlegroups.com...

On 24 Jul., 02:29, Curtis W <cwarre...@gmail.com> wrote:
>
> A numerical IF (I would prefer the term comparison IF)
>

So would I but everything I thoght of that, and thought 'Wow, that's a much
better name', I usually came up with a 'oh yeah, if's are comparative as
well, just boolean. Maybe 'relative comparative if', but that gets
unwieldly.


Reinder Verlinde

unread,
Jul 24, 2008, 12:38:16 PM7/24/08
to
In article
<0ae4b106-2b33-4722...@l64g2000hse.googlegroups.com>,
thomas...@gmx.at wrote:

> > Also, if you design you own language, you might consider a switch
> > variant that has undefined behavior for values not in any 'case'.
>
> I agree in principle, but the Seed7 compiler generates C instead
> of machine code. Therefore I am currently limited to what can
> expressed with C.

?? If you define your switch statement as "behavior is undefined for
values not in any 'case'", your compiler can just generate C switch
statements. These have well-defined behavior, but any well-defined
behavior is good enough for "behavior is undefined". However, if you
leave behavior undefined, a future version of your compiler is free to
use jump tables without range checks for the simple cases.

reinder

Curtis W

unread,
Jul 24, 2008, 7:20:14 PM7/24/08
to

Actually, never mind. I hadn't realized that the OP specifically asked
for implementations.

Gene

unread,
Jul 24, 2008, 10:34:24 PM7/24/08
to
> Instead of marching boldly into the past, I propose to speculate
> a bit.  First of all, there is no need for the compared arguments
> to be numbers.  They could any kind of type that is an order
> type, i.e., any type that has a defined order relationship.

Exactly!

> Then there is the question of what the comparison yields.  In C
> strcmp yields -1, 0, and 1. However this is a hack.  Decent


> languages have a native boolean type with values true and false;
> one could consider having a native three valued type with values
> lt, eq, and gt.
>

The strcmp() convention of negative, zero, or positive integer ought
to work fine. This way a compiler optimizer has maximum
opportunity.

I am surprised no one has mentioned binary search. Suppose we are in C
++ and the "<" and "=" comparison operators are big and expensive.
Then a typical implementation does two hairy binary comparisons when

int search_for(item x, item *a[], int n)
{
int lo = 0;
int hi = n - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (a[mid] == x) return mid;
if (a[mid] < x)
lo = mid + 1;
else
hi = mid - 1;
}
return -1;
}

A solution is to require a 3-way cmp function that returns -1, 0, 1.
(Or translate to your favorite; most will work the same.)

Then branch with a switch.

int search_for(item x, item *a[], int n)
{
int lo = 0;
int hi = n - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
switch ( cmp(a[mid], x) ) {
case -1 : lo = mid + 1; break;
case 0 : return mid;
case +1 : hi = mid - 1; break;
}
}
return -1;
}

Now suppose we add the Perl binary operator <=> to the language, which
can be overloaded. (Perl also has cmp for strings.) The operator
returns a new data type "sign" for trinary relation values. Then a
nice syntax would result if we just allow relational cases in switch
statements (or equivalent in your favorite language). They're only
legal if the switch value has type sign:

int search_for(item x, item *a[], int n)
{
int lo = 0;
int hi = n - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
switch (a[mid] <=> x) {
case < : lo = mid + 1; break;
case = : return mid;
case > : hi = mid - 1; break;
}
}
return -1;
}

This code better reflects the search algorithm. On processors (like
Intel) values of type sign can be represented in condition code
registers. With this we can compile very cleanly to:

/* instructions here compute a[mid]<=> x and leave results in
condition codes */
jle Lt
jeq Eq
hi = mid - 1;
jmp Z;
Lt:
lo = mid + 1;
jmp Z:
Eq:
return mid;
Z:

A regular switch branching on -1,0,1 will test for equality with all 3
values and allow for a fall-through case. This will require a few
more instructions.

Worth the trouble? I agree with the OP that this would be an easy and
elegant addition to most languages. Performance of compiled code is a
very minor additional reason.

0 new messages