www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Suggestion: Change precedence of 'new'

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Sometimes it's handy to invoke a function on a class right after 
creating it:

     new Thread(&func).run();

Unfortunately that doesn't work in D right now.  You have to put 
parentheses around the new expression because it has lower precedence 
than dotExpression:

      (new Thread(&func)).run();

I don't recall how it works in C++, but at least in Java, the first 
version works.

I'm not a grammar guru, so can anyone who is say whether the above 
change would be possible?

Maybe it would muck up construction based on fully qualified names?   So 
that

   new thread.Thread(&func)

would have to become

   new (thread.Thread(&func)

If so that would suck.  But Java is able to make it work somehow, and 
the construct seems to be used quite heavily there (I've been looking at 
a lot of SWT code lately...)

--bb
Apr 09 2008
next sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
I think the problem is in supporting this syntax:

auto x = new package.module.Class;

In which case, differing it from this is difficult:

auto y = new package.module.Class.propertyMethod;

Anyway, I believe the docs say that it is always an error to rely on 
order of operations... perhaps I'm wrong.

-[Unknown]


Bill Baxter wrote:
 Sometimes it's handy to invoke a function on a class right after 
 creating it:
 
     new Thread(&func).run();
 
 Unfortunately that doesn't work in D right now.  You have to put 
 parentheses around the new expression because it has lower precedence 
 than dotExpression:
 
      (new Thread(&func)).run();
 
 I don't recall how it works in C++, but at least in Java, the first 
 version works.
 
 I'm not a grammar guru, so can anyone who is say whether the above 
 change would be possible?
 
 Maybe it would muck up construction based on fully qualified names?   So 
 that
 
   new thread.Thread(&func)
 
 would have to become
 
   new (thread.Thread(&func)
 
 If so that would suck.  But Java is able to make it work somehow, and 
 the construct seems to be used quite heavily there (I've been looking at 
 a lot of SWT code lately...)
 
 --bb
Apr 09 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Unknown W. Brackets wrote:
 I think the problem is in supporting this syntax:
 
 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
 In which case, differing it from this is difficult:
 
 auto y = new package.module.Class.propertyMethod;
 
 Anyway, I believe the docs say that it is always an error to rely on 
 order of operations... perhaps I'm wrong.
Not if the order is well defined, just when two operators have the same precedence. 2 + 5 * 3 should always evaluate to 17, never to 21.
 -[Unknown]
Apr 09 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Robert Fraser wrote:
 Unknown W. Brackets wrote:
 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary. --bb
Apr 09 2008
parent reply Georg Wrede <georg nospam.org> writes:
Bill Baxter wrote:
 Robert Fraser wrote:
 
 Unknown W. Brackets wrote:

 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary.
Just to clarify, how would that look with the proposed precedence?
Apr 10 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Georg Wrede wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:

 Unknown W. Brackets wrote:

 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary.
Just to clarify, how would that look with the proposed precedence?
You mean what does it look like in java? Like this: new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }.run(); (it's creating an anonymous subclass of 'Runnable', and running it.) --bb
Apr 10 2008
parent reply Georg Wrede <georg nospam.org> writes:
Bill Baxter wrote:
 Georg Wrede wrote:
 
 Bill Baxter wrote:

 Robert Fraser wrote:

 Unknown W. Brackets wrote:

 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary.
Just to clarify, how would that look with the proposed precedence?
You mean what does it look like in java? Like this: new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }.run(); (it's creating an anonymous subclass of 'Runnable', and running it.)
So, you gain the omission of one pair of parentheses, but lose in expressional clarity. In the current version, it is very clear to the reader (even to the one not familiar with the particular usage) what is going on. With the proposal, one has to really think hard, if one is not familiar with it from before. That's always a bad sign. I'm not absolutely against this, but some more compelling examples would go a long way.
Apr 10 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
Georg Wrede wrote:
 Just to clarify, how would that look with the proposed precedence?
You mean what does it look like in java? Like this: new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }.run(); (it's creating an anonymous subclass of 'Runnable', and running it.)
So, you gain the omission of one pair of parentheses, but lose in expressional clarity. In the current version, it is very clear to the reader (even to the one not familiar with the particular usage) what is going on. With the proposal, one has to really think hard, if one is not familiar with it from before. That's always a bad sign. I'm not absolutely against this, but some more compelling examples would go a long way.
I don't think that particular example is very difficult to read without the parentheses, but a new anonymous class expression is actually a different type of expression than a new expression, so now we're talking changing the precedence of two expressions.
Apr 10 2008
prev sibling next sibling parent "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
news:ftjqml$2oo4$1 digitalmars.com...
 Sometimes it's handy to invoke a function on a class right after creating 
 it:

     new Thread(&func).run();

 Unfortunately that doesn't work in D right now.  You have to put 
 parentheses around the new expression because it has lower precedence than 
 dotExpression:

      (new Thread(&func)).run();

 I don't recall how it works in C++, but at least in Java, the first 
 version works.
In D, "new" already has higher precedence than "cast", which is more useful, IMHO: #Foo foo = cast(Foo)new Bar; L.
Apr 09 2008
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Bill Baxter Wrote:
 Sometimes it's handy to invoke a function on a class right after 
 creating it:
      new Thread(&func).run();
The syntax of the new operator can be improved. Here Python syntax can't be used (in Python the () operator of the *class* object creates the object instance. In Python classes are objects of a metaclass). Ruby uses a syntax similar to this, and I think it may be fit for D too, solving your problem (that I share with you): Thread(&func).new.run(); Do you see problems with this syntax? Bye, bearophile
Apr 10 2008
parent reply Georg Wrede <georg nospam.org> writes:
bearophile wrote:
 Bill Baxter Wrote:
 
Sometimes it's handy to invoke a function on a class right after 
creating it:
     new Thread(&func).run();
The syntax of the new operator can be improved. Here Python syntax can't be used (in Python the () operator of the *class* object creates the object instance. In Python classes are objects of a metaclass). Ruby uses a syntax similar to this, and I think it may be fit for D too, solving your problem (that I share with you): Thread(&func).new.run(); Do you see problems with this syntax?
New vanishes in the foliage. I think it is important that new is easy to spot when reading code.
Apr 10 2008
parent reply bearophile <bearophileHUGS lycos.com> writes:
Georg Wrede:
 Do you see problems with this syntax?
New vanishes in the foliage. I think it is important that new is easy to spot when reading code.
I see. Well, I presume Ruby people don't have much problems with that syntax. And I think you can set your editor/IDE to show that 'new' in red color ;-) Bye, bearophile
Apr 10 2008
parent Georg Wrede <georg nospam.org> writes:
bearophile wrote:
 Georg Wrede:
 
Do you see problems with this syntax?
New vanishes in the foliage. I think it is important that new is easy to spot when reading code.
I see. Well, I presume Ruby people don't have much problems with that syntax. And I think you can set your editor/IDE to show that 'new' in red color ;-)
:-) But then there are textbooks, normal source code listings on paper, uncolored source code on web pages and blogs, source files viewed with other than a D-aware text reader or editor, etc... Oh, and this NG too.
Apr 10 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Bill Baxter Wrote:

 Robert Fraser wrote:
 Unknown W. Brackets wrote:
 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary. --bb
Why would anyone write code like that in D? First of all a delegate works just as well as a class with one member. Second, if this is simply run like a blocking function call, why not define a nested function and just call it? PS: I'm not trying to knock down your feature request. I just find the example strange. I'm sure there's more useful examples available and you just picked one at random.
Apr 10 2008
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Jason House wrote:
 Bill Baxter Wrote:
 
 Robert Fraser wrote:
 Unknown W. Brackets wrote:
 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary. --bb
Why would anyone write code like that in D? First of all a delegate works just as well as a class with one member. Second, if this is simply run like a blocking function call, why not define a nested function and just call it? PS: I'm not trying to knock down your feature request. I just find the example strange. I'm sure there's more useful examples available and you just picked one at random.
Okay, how about this (admittedly contrived) example? public abstract class A { public final int foo() { // do stuff bar(); // do more stuff & return something } protected abstract void bar(); } void baz() { int k = new class A { protected void bar() { // ... } }.foo(); }
Apr 10 2008
parent Jason House <jason.james.house gmail.com> writes:
Robert Fraser Wrote:

 Jason House wrote:
 Bill Baxter Wrote:
 
 Robert Fraser wrote:
 Unknown W. Brackets wrote:
 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary. --bb
Why would anyone write code like that in D? First of all a delegate works just as well as a class with one member. Second, if this is simply run like a blocking function call, why not define a nested function and just call it? PS: I'm not trying to knock down your feature request. I just find the example strange. I'm sure there's more useful examples available and you just picked one at random.
Okay, how about this (admittedly contrived) example? public abstract class A { public final int foo() { // do stuff bar(); // do more stuff & return something } protected abstract void bar(); } void baz() { int k = new class A { protected void bar() { // ... } }.foo(); }
Actually, I meant in the context of the original proposal new foo().bar
Apr 10 2008
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Jason House wrote:
 Bill Baxter Wrote:
 
 Robert Fraser wrote:
 Unknown W. Brackets wrote:
 I think the problem is in supporting this syntax:

 auto x = new package.module.Class;
The argument (as far as I can tell) is that it would be supported only if trailing parentheses were supplied, so that expression would have to be written as "new package.module.Class().propertyMethod;".
That makes sense. So the rule would be that 'new' munches all the dot-separated identifiers to its right till it hits something besides a dot or an identifier. Here's another one from actual D code ported from Java: (new class Runnable { public void run() { if (canvas.isDisposed()) return; render(); canvas.swapBuffers(); canvas.getDisplay().timerExec(15, this); } }).run(); In Java the parens around that whole mess aren't necessary. --bb
Why would anyone write code like that in D? First of all a delegate works just as well as a class with one member. Second, if this is simply run like a blocking function call, why not define a nested function and just call it? PS: I'm not trying to knock down your feature request. I just find the example strange. I'm sure there's more useful examples available and you just picked one at random.
Yeh, sorry. It wasn't meant to be a convincing argument about why the features is needed. It was just some SWT Java code I happened to be porting yesterday, so it was more just to say "here's another thing that works without parens in the Java way". Unless you're porting Java code, I hope no one does write D code like that. :-) But I have wanted to do things like new Widget(args).enabled = false; --bb
Apr 10 2008
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Bill Baxter escribió:
 Sometimes it's handy to invoke a function on a class right after 
 creating it:
 
     new Thread(&func).run();
 
 Unfortunately that doesn't work in D right now.  You have to put 
 parentheses around the new expression because it has lower precedence 
 than dotExpression:
 
      (new Thread(&func)).run();
It's just because you can ommit the parenthesis in case the constructor (or any function) has no arguments, like new Thread.run Nice, huh? You save yourself a pair of parenthesis, but... --- module one; import std.stdio; class One { int foo; this() { foo = 1; } static class Two { int foo; this() { foo = 2; } } } void main() { auto x = new One.Two; writefln("%s", x.foo); // 1 or 2? :-) } --- I really like how Java handles this: parenthesis are mandatory for methods and constructors. Then you can have things like this: class Foo { int property: void property(int p) { property = p; } } Foo.property --> the variable Foo.property() --> the method In C++ and D, you have to use _property, or fProperty, mProperty, or some other ugly syntax. :(
Apr 11 2008
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Ary Borenszweig wrote:
 In C++ and D, you have to use _property, or fProperty, mProperty, or 
 some other ugly syntax. :(
OT, why does Eclipse do this? It was also required where I used to work (mName for member variables, sName for static variables), but I never asked why.
Apr 11 2008
parent Ary Borenszweig <ary esperanto.org.ar> writes:
Robert Fraser escribió:
 Ary Borenszweig wrote:
 In C++ and D, you have to use _property, or fProperty, mProperty, or 
 some other ugly syntax. :(
OT, why does Eclipse do this? It was also required where I used to work (mName for member variables, sName for static variables), but I never asked why.
These are just guesses: - When you want to autocomplete a field, you type "f" instead of "this." - You never mistake a parameter from a field. But I don't like it. :-P I know, Eclipse colorizes these differently, but it seems the Eclipse guys don't want to assume other developers are using/seeing their code with Eclipse. That's also why, I think, in inherited functions you see: /* * (non-Javadoc) * see foo.Bar.method(String, int) */ public void method(String s, int i) { // ... } In Eclispe you get the marker saying that method is being overriden, but if you open it in a simple text editor, you can't immediately know that. Well... that was until annotations appear, together with Override.
Apr 11 2008
prev sibling parent "Scott S. McCoy" <tag cpan.org> writes:
At the same time, the fact that parenthesis are optional is also quite
nice.

It allows accessing a member to magically become accessing an accessor,
and it eliminates unnecessary parenthesis on multiple statements which
makes trees nicer to access, consider DOM:

document.firstChild.firstChild.lastChild.parentNode;

This is a lot nicer than....

document.getFirstChild().getFirstChild().getLastChild().getParentNode();

To make the example less extreme, it's still nicer than:

document.firstChild().firstChild().lastChild().parentNode() and less
ugly.

But, it's not really a trade off that matters much in the long run.

Cheers,
	Scott S. McCoy

On Fri, 2008-04-11 at 13:46 -0300, Ary Borenszweig wrote:
 I really like how Java handles this: parenthesis are mandatory for 
 methods and constructors.
Apr 11 2008
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Thu, 10 Apr 2008 03:32:01 +0200, Bill Baxter  =

<dnewsgroup billbaxter.com> wrote:

 Sometimes it's handy to invoke a function on a class right after  =
 creating it:

      new Thread(&func).run();

 Unfortunately that doesn't work in D right now.  You have to put  =
 parentheses around the new expression because it has lower precedence =
=
 than dotExpression:

       (new Thread(&func)).run();

 I don't recall how it works in C++, but at least in Java, the first  =
 version works.

 I'm not a grammar guru, so can anyone who is say whether the above  =
 change would be possible?

 Maybe it would muck up construction based on fully qualified names?   =
So =
 that

    new thread.Thread(&func)

 would have to become

    new (thread.Thread(&func)

 If so that would suck.  But Java is able to make it work somehow, and =
=
 the construct seems to be used quite heavily there (I've been looking =
at =
 a lot of SWT code lately...)

 --bb
You can work around this with static opCalls. class foo { static foo opCall() { return new foo(); } int bar() { return 4; } } int a =3D foo().bar; Still requires a parentheses, but you might like it better. -- Simen
Apr 11 2008
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Simen Kjaeraas wrote:
 On Thu, 10 Apr 2008 03:32:01 +0200, Bill Baxter 
 <dnewsgroup billbaxter.com> wrote:
 
 Sometimes it's handy to invoke a function on a class right after 
 creating it:

      new Thread(&func).run();

 Unfortunately that doesn't work in D right now.  You have to put 
 parentheses around the new expression because it has lower precedence 
 than dotExpression:

       (new Thread(&func)).run();

 I don't recall how it works in C++, but at least in Java, the first 
 version works.

 I'm not a grammar guru, so can anyone who is say whether the above 
 change would be possible?

 Maybe it would muck up construction based on fully qualified names?   
 So that

    new thread.Thread(&func)

 would have to become

    new (thread.Thread(&func)

 If so that would suck.  But Java is able to make it work somehow, and 
 the construct seems to be used quite heavily there (I've been looking 
 at a lot of SWT code lately...)

 --bb
You can work around this with static opCalls. class foo { static foo opCall() { return new foo(); } int bar() { return 4; } } int a = foo().bar; Still requires a parentheses, but you might like it better.
No. I'm not going to start writing constructors for every class twice just to be able to save on some parenthesis in certain situations. If making "new foo().bar" work is going to have any undesirable side effects than it's not worth it. It just seemed to me that it might be a simple change to the grammar. --bb
Apr 11 2008