assert-like debug { /* code */ } feature?

  • Thread starter Andreas Leitgeb
  • Start date
A

Andreas Leitgeb

There were recently some threads in which "assert" occurred,
and which raised a question in me about whether it would
be useful to have nested code blocks executed if and only if
the code was compiled to also do "assert"s.

e.g., I could already do this:
assert myDebuggingMethod();
and have a new method myDebuggingMethod(), that doesn't
do anything relevant to the algorithm itself, but does
some costly gathering of data to determine if the program
is still working as intended.

If this myDebuggingMethod() needed to read some local
variables as well, I'd have to pass each as an argument
to the method. Not to mention that the checking code
itself would not be in eyesight at the spot where it
would be (probably solely) used.

If there were a feature like:
debug {
int check;
// some costly code to determine some supposed invariant
assert check==42;
}
and the whole block would be compiled or ignored by the same
criteria as assertions are now, then I think this would be useful.

Has something like that been discussed already, did I miss
some strong arguments against it? Does anyone happen to agree
on its usefulness?
 
A

Andreas Leitgeb

Eric Sosman said:
The myDebuggingMethod() approach is one possibility.
Another is to (ab)use the assert statement itself to discover
whether assertions are enabled or disabled.

That's two more or less^H^H^H^Heven-more crude hacks.

Another approach could be that the compiler simulates/adds(*)
a static final boolean field to each class, that tells if
the class is being compiled with assertions or not.
That would be like the trick you offered, but without the
querying misuse of assert, and with the whole "if-statement"
really omitted for a non-asserting build.

*: I'd even prefer the "adds": then one could query a .class
file for whether it has been compiled with or without assertions
 
S

Stefan Ram

Andreas Leitgeb said:
debug {
int check;
// some costly code to determine some supposed invariant
assert check==42;
}


public class Main
{ public static void main( final java.lang.String[] args )
{ assert new java.util.concurrent.Callable<java.lang.Boolean>()
{ public java.lang.Boolean call()
{ java.lang.System.out.println( "alpha" ); return true; }}.call(); }}

/*
alpha
*/
 
T

Tegiri Nenashi

        boolean asserting = false;
        assert (asserting = true);  // just one =

Hmm, I was unaware of assignment being interpreted as predicate. Just
checked this weird code:

boolean asserting = false;
if( asserting == (asserting = true) )
asserting = (asserting = true);

Why on earth this is allowed?
 
T

Tegiri Nenashi

     The assignment operator stores a value to its left-hand
operand, and yields that value as the value of its expression.
That's why you can do

        while ( (line = reader.readLine()) != null )
                      ^                   -- operator
                 ^^^^^^^^^^^^^^^^^^^^^^^^ -- expression

     In the assert hack shown above, the value assigned (hence
the value of the expression) is a boolean, and a boolean can
be tested by if, while, for, ?:, assert, and maybe a few
other things I've overlooked.

Consider:

boolean x = false;
if( x = true );

versus

int y = 0;
if( y = 1 );

Why the first one is allowed and the second don't?

I don't think "operator is a predicate" idea has any merit.
 
T

Tegiri Nenashi

Because the expression in the "if" statement has evaluate to the boolean  
type.  In your second example, the expression evaluates to int, which is  
of course not boolean.

Sure you are aware of the fact that both cases are legal in C. The
only reason why it has been changed in Java is to prevent 99.9% of the
cases where programmer made a typo and missed one extra "=". Now you
are saying that fixing the case where equality is between integer
types is OK, but with booleans it is no longer OK? (In the example
above checking if boolean is true certainly qualifies this code snppet
as written by newbie. Change this to equality comparison of two
boolean varibles).
 
L

Lew

Tegiri said:
Sure you are aware of the fact that both cases are legal in C. The

That's irrelevant to Java.
only reason why it has been changed in Java is to prevent 99.9% of the
cases where programmer made a typo and missed one extra "=". Now you

No, that's not correct. It is changed in Java because, as Peter and
Eric point out, the type of the assignment is wrong. It's still
perfectly legal to use assignment expressions '(x = foo)' in Java
wherever an expression of that type is allowed.
are saying that fixing the case where equality is between integer
types is OK, but with booleans it is no longer OK?

There was no "fixing the case", in part because the "case" isn't
broken to begin with. The issue isn't the '=' operator versus the
'==' operator, but the expression type of 'int' not being compatible
with the expression type of 'boolean'. Java (like C) allows you to
use the '=' operator to construct an expression of any type. There is
no difference between the two in that regard. Thus, it is perfectly
legal to code:

int i;
int j = (i = 3);

Just not:

int i;
boolean j = (i = 3);
 
T

Tegiri Nenashi

     Because the type of `x = true' is boolean, while the
type of `y = 1' is int.  

Here is the essence of our disagreement. Contrary to what gospel
(sorry, JLS) may insist, assignment is not a variable. It is a way to
apply changes to the state of the world. Therefore, assignment doesn't
have a type.
 
K

Kenny Riodan

Here is the essence of our disagreement. Contrary to what gospel
(sorry, JLS) may insist, assignment is not a variable.

What are you on about?

Of course assignment is not a variable.
Assignment is an expression.
assignment doesn't have a type.

C, C++, and Java all disagree with you here.
For example, this allows you to write:

int a, b, c;
a = b = c = 7;

which is parsed into

a = (b = (c = 7));

which means

c=7;
a = (b = 7);

which means

c=7;
b=7;
a=7;
 
T

Tegiri Nenashi

What are you on about?

Of course assignment is not a variable.
Assignment is an expression.

You are right, I have to make a correction. Not only (explicitly
declared) variables have a type, but also expressions over the
variables; e.g given "int x,y;" the expression "x+y" is of type int.

Now is assignment realy an expression? I don't mean that you answer
that by trivially checking your favorite language grammar. Expression
is a way to construct some values from existing ones by applying some
functions (with many functions being built-in operations). From this
perspective assignment is not an expression.
C, C++, and Java all disagree with you here.
For example, this allows you to write:

int a, b, c;
a = b = c = 7;

You don't have to move all the variables to the beginning of the
block. You can declare variables as soon as they are needed. Code
locality -- declaration close to the usage -- is a good thing. From
that perspective the advantage of the feature you mentioned is
minuscule.
 
J

Joshua Cranmer

Tegiri said:
Here is the essence of our disagreement. Contrary to what gospel
(sorry, JLS) may insist, assignment is not a variable. It is a way to
apply changes to the state of the world. Therefore, assignment doesn't
have a type.

It's not a variable. Plenty of non-variable things have types. 5 is not
variable, yet it clearly has a type of |int|. Things that have types are
called `expressions', and assignments are expressions in MANY languages,
including (but not limited to):

* Awk
* C
* C++
* Java
* Javascript (sorry, ECMAScript)
* Python
* PHP

In fact variables (or the values thereof, to be precise) are themselves
expressions.

Would you like citations from ISO C++ and other language specs, or are
these explanations sufficient?
 
K

Kenny Riodan

You are right, I have to make a correction. Not only (explicitly
declared) variables have a type, but also expressions over the
variables; e.g given "int x,y;" the expression "x+y" is of type int.
Indeed.

Now is assignment realy an expression? I don't mean that you answer
that by trivially checking your favorite language grammar. Expression
is a way to construct some values from existing ones by applying some
functions (with many functions being built-in operations). From this
perspective assignment is not an expression.

It's useful as a form of currying. And it's purely up to a
language designer or a library designer's choice. And it's
purely subjective and depends on individual's taste.

For example, even method calls can be curried.

Suppose you have a File object, which has a "write(String)" method.
Now, the library designer could have implemented it
without currying:

void write(String x) { for(char c: x) this.writeChar(c); }
Then to write 3 strings, you would write:
file.write("A");
file.write("B");
file.write("C");

Or the library designer could have implemented it
with currying (an example of this is the StringBuilder class
in Java standard library)

File write(String x) { for(char c: x) this.writeChar(c); return
this; }
Then to write 3 strings you can write:
file.write("A").write("B").write("C);

And you can ask the same question you just asked me earlier:
since write(String) is obviously just an operation,
should *it* be an expression? should it have a type?

Answer is... *drum roll* whatever the language and library designer
chose!
You don't have to move all the variables to the beginning of the
block. You can declare variables as soon as they are needed. Code
locality -- declaration close to the usage -- is a good thing. From
that perspective the advantage of the feature you mentioned is
minuscule.

You utterly missed my point.

That construct is legal and used all over the place in
C, C++, C#, and Java code.

Whether *you* like it or not is your own damned business.
We're discussing legalities here, not your own pet language.
 
J

Joshua Cranmer

Tegiri said:
Now is assignment realy an expression? I don't mean that you answer
that by trivially checking your favorite language grammar. Expression
is a way to construct some values from existing ones by applying some
functions (with many functions being built-in operations). From this
perspective assignment is not an expression.

Yes. An expression is a series of values (literals, variable references,
etc.) joined by operators. Essentially, if <x> and <y> are expressions,
and <op> is an operator, <x> <op> <y> is an expression [1]. So what are
operators? There are arithmetic operators (+, -, *, and /), bitwise
operators (&, ^, |), assignment operators (=, <op>=), and... Hey, wait,
'=' is an operator!

Another way of looking at it is that the increment/operators are merely
shorthands for += or -= 1 (prefix, in this case). If you look at like
that, you are modifying the value of the reference (variable, field,
etc.) and then wishing to use it immediately--say you were in the middle
of a long expression. I do stuff like this a fair amount:

int operand = (bytes << 8 & 0xff) | (bytes[++i] & 0xff);

Which is the same as this, in essence:

int operand = (bytes << 8 & 0xff) | (bytes[i+=1] & 0xff);

The only thing special about assignment is that it stores it in a
variable. Which isn't special, if you have reference-like features. C's
doFoo(&variable) is really an assignment in disguise. In fact, the
notion of a function like this is not uncommon:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

So why should the assignment operator be so special that it's not an
expression?
You don't have to move all the variables to the beginning of the
block. You can declare variables as soon as they are needed. Code
locality -- declaration close to the usage -- is a good thing. From
that perspective the advantage of the feature you mentioned is
minuscule.

Resetting a lot of variables in the middle of a function is a use case I
can imagine.
 
J

Joshua Cranmer

Tegiri said:
Sure you are aware of the fact that both cases are legal in C. The
only reason why it has been changed in Java is to prevent 99.9% of the
cases where programmer made a typo and missed one extra "=".

No. Java made a decision to not make primitive types and object
references convertible to booleans. In fact, it differs from its
predecessors in having a boolean type that is not merely a special case
of the integer. Merely omitting an "=" may have been one of the factors,
but there are several others, most notably an increased sense of type
safety that comes with separating the two. Besides, |if (b != 0)| is
clearer to read than |if (b)|.

C is incredibly lax on type safety. Java is the polar opposite when it
comes to type safety. Also, C didn't until recently have something
resembling a boolean, and even then it's still really an integer in
disguise.
 
T

Tegiri Nenashi

It's useful as a form of currying. And it's purely up to a
language designer or a library designer's choice. And it's
purely subjective and depends on individual's taste.

For example, even method calls can be curried.

Suppose you have a File object, which has a "write(String)" method.
Now, the library designer could have implemented it
without currying:

void write(String x)  { for(char c: x)  this.writeChar(c); }
Then to write 3 strings, you would write:
file.write("A");
file.write("B");
file.write("C");

Or the library designer could have implemented it
with currying (an example of this is the StringBuilder class
in Java standard library)

File write(String x) {  for(char c: x) this.writeChar(c);  return
this; }
Then to write 3 strings you can write:
file.write("A").write("B").write("C);

What is so special about this currying technique? I would imagine that
if I want to write multiple strings into a file, more often than not
this need would have arisen in the context of loop. From that
perspective, the syntactic ability to express a sequence of
assignments as one unwieldly expression is cute but pretty much
useless.
 
K

Kenny Riodan

What is so special about this currying technique? I would imagine that
if I want to write multiple strings into a file, more often than not
this need would have arisen in the context of loop. From that
perspective, the syntactic ability to express a sequence of
assignments as one unwieldly expression is cute but pretty much
useless.

Two answers:

First answer, a technical answer: in the StringBuilder's case, the
designers knew
that people often want to write things like this: (and if you don't
believe me,
just take any casual glance at JSP pages people often write):

output.write("Your name: " + name + "<br>Your address :" + address);

But doing this way is stupid, since it will construct multiple
temporary String concatenations unnecessarily.
Instead, the *efficient* way of writing this (since "output" object
already has its own buffering) is like so:

output.write("Your name: ");
output.write(name);
output.write("<br>Your address :");
output.write(address);

But this gets *really* tedious; what used to be "1 line"
turns into 4, just for *efficiency sake*.
But if currying is allowed, you can get best of both worlds:

What is so special about this currying technique? I would imagine that

Second answer: *NOBODY* said it was special. I didn't say it's
special.
I said it's up to the library designer's personal taste,
and I emphasized that it's purely subjective choice.

You have very poor reading comprehension indeed.
 
T

Tegiri Nenashi

... in the StringBuilder's case, the
designers knew
that people often want to write things like this: (and if you don't
believe me,
just take any casual glance at JSP pages people often write):

  output.write("Your name: " + name + "<br>Your address :" + address);

But doing this way is stupid, since it will construct multiple
temporary String concatenations unnecessarily.

Are you sure the users are stupid; not the compiler optimizer
developers?
 
K

Kenny Riodan

Are you sure the users are stupid; not the compiler optimizer
developers?

You are really not very bright.

I picked the StringBuilder example (which happens to be in the Java
standard library) so its meaning is obvious to the Java compiler.
But as was said many times, this "style" is applicable
to any library design, and given something like a
ICMP-messaging sending library, then the meaning of:

ICMP.write("A");
ICMP.write("B");

is very different from

ICMP.write("A" + "B");

since the first would send 2 separate ICMP packets
with distinct ID and the second would send a single ICMP packet.
There is no way for the compiler to discern whether
the user intended one or the other.

And you're just grasping onto straws. Just give it up.

This idiom is extremely popular in many languages and many libraries,
and when chosen well, it makes user code both concise
and a joy to read.
 
T

Tegiri Nenashi

You are really not very bright.

I picked the StringBuilder example (which happens to be in the Java
standard library) so its meaning is obvious to the Java compiler.
But as was said many times, this "style" is applicable
to any library design, and given something like a
ICMP-messaging sending library, then the meaning of:

ICMP.write("A");
ICMP.write("B");

is very different from

ICMP.write("A" + "B");

since the first would send 2 separate ICMP packets
with distinct ID and the second would send a single ICMP packet.
There is no way for the compiler to discern whether
the user intended one or the other.

I don't see how your second example is related to the first. In the
string concatenation example:

output.write("Your name: " + name + "<br>Your address :" + address);

we have a very intuitive high level expression with rather poor
execution as a sequence of low level string concatenation calls. In
the ICMP-messaging example

ICMP.write("A");
ICMP.write("B");

we have a low-level description how to excecute things. Sure there are
two steps that can be separated:
* String building
* Message sending
Both can be accomodated without currying, of course. Moreover, it
looks that this example demonstates the opposite of what you are
trying to convey. Writing it in currying style:

ICMP.write("A").write("B");

is asking for a trouble!
 
K

Kenny Riodan

I don't see how your second example is related to the first.

In that both examples use currying.
The semantics was not what was important.
Rather, the style of invoking a *series* of function call is.

Repeat after me: the specific example's semantics is not important.
In the string concatenation example:
output.write("Your name: " + name + "<br>Your address :" + address);
we have a very intuitive high level expression with rather poor
execution as a sequence of low level string concatenation calls.

No you're wrong.

Both StringBuilder and ICMP are output streams that
take a series of objects to output. StringBuilder
happens to take Strings and merge them into a big String,
so the fact that the user wrote redundant String concatenations
is stupid. But ICMP's output is ICMP packets,
and the String concatenation (if the user intended them) is *crucial*.
It is crucial that the first ICMP message says "route set 1.2.3.4"
rather than 2 separate ICMP messages of "route set 1.2" and ".3.4"
Writing it in currying style:
ICMP.write("A").write("B");
is asking for a trouble!

You are not convincing.

ICMP.write("A").write("B")
as a short hand for
ICMP.write("A") followed by ICMP.write("B")
is very handy and very concise.
I see nothing disastrous there.

Let's take *yet another example*. Take the very popular
3rd party layout manager "MiGLayout" that people are so in love with
that they are asking for it to be added to into Java 7.
MiGLayout uses currying extensively, so that
you can do things like

x.add(new JButton("A")).add(new JCheckbox("B"))

When done tastefully, this currying style makes the code
very concise and a joy to read. So I've presented 3 real world
examples: StringBuilder, ICMP, and MiGLayout.
Their *semantics* doesn't matter.
We're talking about a *style* of writing.

So stop your *compiler writer* bashing (when you complained
that the compiler was stupid to not shift the String
concatenation into the StringBuilder)

And stop your *language* bashing (when you complained
that in Java/C/C++/C#/Awk/PHP/..., the = operator
shouldn't be an expression)

The others are right. You are a troll. *Good bye*. Plonk!
 

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,992
Messages
2,570,220
Members
46,805
Latest member
ClydeHeld1

Latest Threads

Top