November 21, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Denis Koroskin | On 2008-11-19 12:49:14 -0500, "Denis Koroskin" <2korden@gmail.com> said: > It's simply broken! You say that empty pair of parens is equivalent to none of them and thus it is allowed to omit them, but it's not true at all. There are lots of examples where "auto foo = bar();" != "auto foo = bar;" and "auto foo = obj.bar();" != "auto foo = obj.bar;" (delegates, class/struct instances with overloaded opCall, etc). As much as I like the no-parens function call syntax, I have to agree with you: it bring inconsistencies. > - such a duality is confusing (when may you omit the parens and when you may not?) Where it becomes confusing is where you try to call the return value of a function, or a no-argument function template. While the most common case (simple function call) may be working right, the no-parens function call syntax creates many not-so-rare corner case we have to deal with. Those cases make it confusing. > - it makes the language more complex (rules are so complex that hardly anyone fully understands them) I don't think each rule for each callable type is in itself that complex, but mixing them leads to complexity. > - it leads to code inconsistency (half of the programmers remove an "extra" pair of parens and other half preserve them) Indeed. I don't think it's bad in itself to have two ways to write something. After all, you can call directly someStruct.opAdd if you prefer that to writing "+". The problem is that in some cases (function pointers, delegates, opCall) it changes the meaning while in other (plain function) it means the same thing. That's inconsistent, it prevents interchangability between those types, and it becomes confusing when using them together. > - it is a source of many compiler bugs (this and lots of related ones) I'm not sure having bugs in the compiler is a valid argument against the syntax. Creating a whole new property syntax is bound to have bugs too. > - it contributes to user code bugs that are hard to find at times ("oops, I missed a pair of parens. God, I thougth that they were optional"). Indeed. So as I said above, I agree that no-parens function calls make the language inconsistant. I still like it because I find it aesthetically pleasing and because it simplifies the concept of properties by making them simple function calls, but at the same time I'm quite annoyed by the inconsistencies. -- Michel Fortin michel.fortin@michelf.com http://michelf.com/ | |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | "Jarrett Billingsley" <jarrett.billingsley@gmail.com> wrote in message news:mailman.19.1227139335.22690.digitalmars-d@puremagic.com... > On Wed, Nov 19, 2008 at 4:59 PM, Brian <digitalmars@brianguertin.com> wrote: >> I don't understand why we wouldn't want properties either. Another issue I've had a couple times, although there might be a good reason for this I'm not aware of: >> >> class Foo { >> int x; >> } >> >> void set(inout int x) { >> x = 10; >> } >> >> void main() { >> auto foo = new Foo(); >> set(foo.x); // This works fine >> } >> >> But then if you need to make x a property: >> >> class Foo { >> int _x; >> >> int x() { return _x; } >> int x(int val) { return _x = val; } >> } >> >> You get "Error: foo.x() is not an lvalue" > > That one's trickier, even if you did have properties. Even "true" properties would still boil down to a function call. Set expects a reference to an integer. How do you convert getter/setter functions into an integer? > class Foo { // This syntax is a modified version of C#'s properties int x { get { return x.rawValue; }; set { x.rawValue = newValue; } } } void makeTen(inout int x) { x = 10; } void main() { int i; auto foo = new Foo(); makeTen(i); // Ok // compiler knows that foo.x is an int property // and turns this: makeTen(foo.x); // into this: auto _foo_x = foo.x; makeTen(_foo_x); foo.x = _foo_x; // and finally this: auto _foo_x = foo.x.get(); makeTen(_foo_x); foo.x.set(_foo_x); } > It doesn't work now because foo.x is a function, not an int. > > Also, I wonder if ref returns could help here.. | |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | "Michel Fortin" <michel.fortin@michelf.com> wrote in message news:gg6c9q$1p2r$1@digitalmars.com... > On 2008-11-19 12:49:14 -0500, "Denis Koroskin" <2korden@gmail.com> said: > >> It's simply broken! You say that empty pair of parens is equivalent to none of them and thus it is allowed to omit them, but it's not true at all. There are lots of examples where "auto foo = bar();" != "auto foo = bar;" and "auto foo = obj.bar();" != "auto foo = obj.bar;" (delegates, class/struct instances with overloaded opCall, etc). > > As much as I like the no-parens function call syntax, I have to agree with you: it bring inconsistencies. > >> - such a duality is confusing (when may you omit the parens and when you may not?) > > Where it becomes confusing is where you try to call the return value of a function, or a no-argument function template. While the most common case (simple function call) may be working right, the no-parens function call syntax creates many not-so-rare corner case we have to deal with. Those cases make it confusing. > >> - it makes the language more complex (rules are so complex that hardly anyone fully understands them) > > I don't think each rule for each callable type is in itself that complex, but mixing them leads to complexity. > >> - it leads to code inconsistency (half of the programmers remove an "extra" pair of parens and other half preserve them) > > Indeed. I don't think it's bad in itself to have two ways to write something. After all, you can call directly someStruct.opAdd if you prefer that to writing "+". > > The problem is that in some cases (function pointers, delegates, opCall) it changes the meaning while in other (plain function) it means the same thing. That's inconsistent, it prevents interchangability between those types, and it becomes confusing when using them together. > That's why I like the consistency other languages have of: - With parens: Invoke function - Without parens: Refer to function itself Example of preferred syntax: class Beeper { void beep() {...} } void main() { auto beeper = new Beeper(); // Beep beeper.beep(); // Make a beeping delegate auto dgBeep = beeper.beep; // Beep twice later doLater(dgBeep); doLater(beeper.beep); //Error: doLater expects "void delegate(void)", not "void" doLater(beeper.beep()); } >> - it is a source of many compiler bugs (this and lots of related ones) > > I'm not sure having bugs in the compiler is a valid argument against the syntax. Creating a whole new property syntax is bound to have bugs too. > >> - it contributes to user code bugs that are hard to find at times ("oops, I missed a pair of parens. God, I thougth that they were optional"). > > Indeed. > > So as I said above, I agree that no-parens function calls make the language inconsistant. I still like it because I find it aesthetically pleasing and because it simplifies the concept of properties by making them simple function calls, but at the same time I'm quite annoyed by the inconsistencies. > > -- > Michel Fortin > michel.fortin@michelf.com > http://michelf.com/ > | |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | On Tue, Nov 25, 2008 at 10:44 PM, Nick Sabalausky <a@a.a> wrote:
> // compiler knows that foo.x is an int property
> // and turns this:
> makeTen(foo.x);
>
> // into this:
> auto _foo_x = foo.x;
> makeTen(_foo_x);
> foo.x = _foo_x;
>
> // and finally this:
> auto _foo_x = foo.x.get();
> makeTen(_foo_x);
> foo.x.set(_foo_x);
I considered this, but what if your setter/getter had some kind of side effect? I know, it's probably a little thing to worry about, but still, I would have intuitively expected it to have been evaluated each time the ref parameter was accessed in the function instead of just once before and after the call.
| |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | Nick Sabalausky
> That's why I like the consistency other languages have of:
> - With parens: Invoke function
> - Without parens: Refer to function itself
> Example of preferred syntax:
> ...
I agree, this is better (in Python there's such syntax).
(I am hopeful for the future of D because I've seen there are lot of people in this neswgroup that seem to have better ideas :-) ).
In alternative, you may also require the & to refer to the function, this makes the syntax more explicit and makes the compiler raise an error if you forget both parens or &:
auto x = foo(); // call the callable
auto x = &foo; // delegate or function pointer or closure
auto x = foo; // syntax error
Bye,
bearophile
| |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | "Jarrett Billingsley" <jarrett.billingsley@gmail.com> wrote in message news:mailman.59.1227675354.22690.digitalmars-d@puremagic.com... > On Tue, Nov 25, 2008 at 10:44 PM, Nick Sabalausky <a@a.a> wrote: >> // compiler knows that foo.x is an int property >> // and turns this: >> makeTen(foo.x); >> >> // into this: >> auto _foo_x = foo.x; >> makeTen(_foo_x); >> foo.x = _foo_x; >> >> // and finally this: >> auto _foo_x = foo.x.get(); >> makeTen(_foo_x); >> foo.x.set(_foo_x); > > I considered this, but what if your setter/getter had some kind of side effect? I know, it's probably a little thing to worry about, but still, I would have intuitively expected it to have been evaluated each time the ref parameter was accessed in the function instead of just once before and after the call. I thought about that too, but the only realistic examples of that I can think of would involve writing getters/setters that abuse the whole point of property syntax. I'm not completely certain, but I think this might be an issue that's akin to using operator overloading to make '*' peform a subtraction. Can anyone think of any non-abusive case where the above would fail? Maybe something with threads and synchronization? Another idea, but possibly messy: Maybe there could be some automatic behind-the-scenes templatization/overloading such that: If there's a function ("bar") that has a parameter passed by reference ("x"), and you try to pass "bar" a property (of the correct type), then an overloaded version of "bar" is created which replaces accesses to x with calls to x's getter/setter. Ie: void bar(inout int x) { x = x + 2; } void main() { int i; auto foo = new Foo(); bar(i); bar(foo.x); // When the compiler detects the above line, // it generates the following overload of bar: } // Automatically generated by compiler, // unless "bar(foo.x);" above is commented out. void bar(inout property!(int) x) // "property!(T)" is either built-in or part of the core library { x.setter(x.getter() + 2); } Although, I suppose that might still create an excess of extra functions when using dynamically-linked libraries (or maybe not, because it would probably only be needed on inout params, and I don't think it's common to have a large number of those). | |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | On Wed, Nov 26, 2008 at 8:12 AM, Nick Sabalausky <a@a.a> wrote:
> Another idea, but possibly messy:
> Maybe there could be some automatic behind-the-scenes
> templatization/overloading such that: If there's a function ("bar") that has
> a parameter passed by reference ("x"), and you try to pass "bar" a property
> (of the correct type), then an overloaded version of "bar" is created which
> replaces accesses to x with calls to x's getter/setter.
>
> Ie:
>
> void bar(inout int x)
> {
> x = x + 2;
> }
>
> void main()
> {
> int i;
> auto foo = new Foo();
> bar(i);
>
> bar(foo.x);
> // When the compiler detects the above line,
> // it generates the following overload of bar:
> }
>
> // Automatically generated by compiler,
> // unless "bar(foo.x);" above is commented out.
> void bar(inout property!(int) x) // "property!(T)" is either built-in or
> part of the core library
> {
> x.setter(x.getter() + 2);
> }
>
> Although, I suppose that might still create an excess of extra functions when using dynamically-linked libraries (or maybe not, because it would probably only be needed on inout params, and I don't think it's common to have a large number of those).
It would also make it difficult to have virtual methods with ref parameters, since the compiler might have to generate 2 ^ (num ref params) overloads of each such method.
| |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | "Jarrett Billingsley" <jarrett.billingsley@gmail.com> wrote in message news:mailman.61.1227711020.22690.digitalmars-d@puremagic.com... > On Wed, Nov 26, 2008 at 8:12 AM, Nick Sabalausky <a@a.a> wrote: >> Another idea, but possibly messy: >> Maybe there could be some automatic behind-the-scenes >> templatization/overloading such that: If there's a function ("bar") that >> has >> a parameter passed by reference ("x"), and you try to pass "bar" a >> property >> (of the correct type), then an overloaded version of "bar" is created >> which >> replaces accesses to x with calls to x's getter/setter. >> >> Ie: >> >> void bar(inout int x) >> { >> x = x + 2; >> } >> >> void main() >> { >> int i; >> auto foo = new Foo(); >> bar(i); >> >> bar(foo.x); >> // When the compiler detects the above line, >> // it generates the following overload of bar: >> } >> >> // Automatically generated by compiler, >> // unless "bar(foo.x);" above is commented out. >> void bar(inout property!(int) x) // "property!(T)" is either built-in or >> part of the core library >> { >> x.setter(x.getter() + 2); >> } >> >> Although, I suppose that might still create an excess of extra functions when using dynamically-linked libraries (or maybe not, because it would probably only be needed on inout params, and I don't think it's common to have a large number of those). > > It would also make it difficult to have virtual methods with ref parameters, since the compiler might have to generate 2 ^ (num ref params) overloads of each such method. But how often are "inout" params really used anyway? Plus, unless there's dynamic library loading going on, it would only have to generate the ones that are actually used. I still prefer my original suggestion though. This is just in the case that my original suggestion turns out to have problems that realistically crop up even when not abusing property syntax. | |||
November 26, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | On Wed, Nov 26, 2008 at 4:07 PM, Nick Sabalausky <a@a.a> wrote: > But how often are "inout" params really used anyway? I use them a lot when passing nontrivial structs around. > Plus, unless there's > dynamic library loading going on, it would only have to generate the ones > that are actually used. No; the problem manifests itself whenever separate compilation is used as well, including not only compiling normal programs, but also using statically-linked libraries. | |||
November 27, 2008 Re: Weird template error | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | Nick Sabalausky Wrote: > That's why I like the consistency other languages have of: > - With parens: Invoke function > - Without parens: Refer to function itself It sounds nice, but then this is what may happen: http://groups.google.com/group/comp.lang.python/browse_thread/thread/1173059b4c786e4b# That's why I have suggested a more explicit syntax, to avoid mistakes, that only adds a char (&): auto x = foo(); // call the callable auto x = &foo; // delegate or function pointer or closure auto x = foo.sizeof; // OK, x becomes 4 or 8, etc. auto x = foo; // syntax error Bye, bearophile | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply