www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - about const and immutable (again)

reply Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
Hi, guys.

I just made my handy parsing struct take an arbitrary range, instead
of a dstring and immediately rain head-first into a brick wall of
errors.

There's this function:
    bool next(bool function(ElementType!InputType) pred)

, where InputType is bound to be dstring and which gets called like this:
    parser.next(&isAlpha)

, where isAlpha is from std.uni.
When i do that, i get this error:
    Error: cannot implicitly convert expression (& isAlpha) of type
bool function(dchar c) pure nothrow  safe to bool
function(immutable(dchar))

Yes, I understand why do i get this error.
What i don't understand is: does the dchar being immutable really
change anything?
I would, if dchar was indirected type, but it's not. isAlpha has no
way to change my original dchar, that i passed it.
What's the point of disallowing this?
And by `this` i mean, initializing mutable cariables of non-indirected
types with immutable values of those types?

Cheers,
Gor.
Oct 06 2011
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 06 Oct 2011 10:56:43 -0400, Gor Gyolchanyan  
<gor.f.gyolchanyan gmail.com> wrote:

 Hi, guys.

 I just made my handy parsing struct take an arbitrary range, instead
 of a dstring and immediately rain head-first into a brick wall of
 errors.

 There's this function:
     bool next(bool function(ElementType!InputType) pred)

 , where InputType is bound to be dstring and which gets called like this:
     parser.next(&isAlpha)

 , where isAlpha is from std.uni.
 When i do that, i get this error:
     Error: cannot implicitly convert expression (& isAlpha) of type
 bool function(dchar c) pure nothrow  safe to bool
 function(immutable(dchar))

 Yes, I understand why do i get this error.
 What i don't understand is: does the dchar being immutable really
 change anything?

What it does is make it so during the function, the parameter cannot be changed. It technically has no effect on what you can pass to the function, since as you rightly point out, ints implicitly cast between const, immutable, and mutable. Why did someone do it? To ensure they didn't accidentally write code that changed the value inside the function. The compiler might also use that information to do some optimization (i.e. avoid reloading into a register), but I doubt it's necessary for that. To answer your underlying question, why doesn't the delegate "just work"? It's because D does not allow implicit casting of delegates or functions at all. I assume this will get better at some point, because implicit casting of delegates would make things just so much smoother in generic programming. -Steve
Oct 06 2011
parent reply Don <nospam nospam.com> writes:
On 06.10.2011 20:56, Steven Schveighoffer wrote:
 On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). In fact, nobody actually wrote the immutable(dchar) function, it's just that the element type is immutable(dchar). However, the reasons why someone would want to create a function that takes an immutable(dchar) function are as I stated -- so you don't accidentally change the value.

That seems like the discussed-and-discarded 'final' storage class for parameters. But this is worse. It has an *enormous* cost. Making immutable(dchar) parameters different from dchar causes *massive* code bloat. Every n parameter template gets 3^^n copies!! And that has a speed cost (use of code cache, branch prediction, etc). You can see the 2^^n explosion in action in std.writefln; executables bloat up enormously. But it gets worse -- it makes it harder to write templates correctly. For example, if the signature is: bool foo(X)(X a, X b) if (is(X : double)) {...} then foo doesn't accept (double, const(double)). And it's entirely unnecessary. The question of whether a function can modify its value parameters is an internal implementation detail of that function. It has no consequences for the caller, so it shouldn't be externally visible. Nobody else needs to know or care. We need to reconsider this. I think it's the way it is by accident; I don't remember any discussion about it.
 Still no excuse that delegates cannot be implicitly cast to compatible
 versions.

Oct 10 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/10/11 5:55 PM, Don wrote:
 On 06.10.2011 20:56, Steven Schveighoffer wrote:
 On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). In fact, nobody actually wrote the immutable(dchar) function, it's just that the element type is immutable(dchar). However, the reasons why someone would want to create a function that takes an immutable(dchar) function are as I stated -- so you don't accidentally change the value.

That seems like the discussed-and-discarded 'final' storage class for parameters. But this is worse. It has an *enormous* cost.

Walter and I have agreed for a long time that upon function calls with by-value passing, there should be some simple transforms done: 1. If a parameter has no indirections, qual(T) becomes T. 2. qual(T[]) becomes qual(T)[]. 3. qual(T*) becomes qual(T)*. This would improve many aspects of the language. Walter never got to implementing it, but I'm bringing this up in case one of the wonderful compiler contributors would want to take it up. Again, I have reasons to believe Walter would approve of the change. Thanks, Andrei
Oct 10 2011
parent Don <nospam nospam.com> writes:
On 11.10.2011 03:29, Andrei Alexandrescu wrote:
 On 10/10/11 5:55 PM, Don wrote:
 On 06.10.2011 20:56, Steven Schveighoffer wrote:
 On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). In fact, nobody actually wrote the immutable(dchar) function, it's just that the element type is immutable(dchar). However, the reasons why someone would want to create a function that takes an immutable(dchar) function are as I stated -- so you don't accidentally change the value.

That seems like the discussed-and-discarded 'final' storage class for parameters. But this is worse. It has an *enormous* cost.

Walter and I have agreed for a long time that upon function calls with by-value passing, there should be some simple transforms done: 1. If a parameter has no indirections, qual(T) becomes T. 2. qual(T[]) becomes qual(T)[]. 3. qual(T*) becomes qual(T)*. This would improve many aspects of the language. Walter never got to implementing it, but I'm bringing this up in case one of the wonderful compiler contributors would want to take it up. Again, I have reasons to believe Walter would approve of the change. Thanks, Andrei

Excellent! That'd be a huge improvement.
Oct 10 2011
prev sibling next sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
I see. Thanks for the detailed answer.
I love D's support for functional programming. Everything about it,
except the readability of function and delegate literals:
    * Function and delegate literals are way too long because of the
"function" and "delegate" keywords being too long to be used inside
expressions.
    * One-liners introduce extra braces and a "return" keyword, which
further litters the supposedly small expression, containing a literal.
    * Parameter types are always required, despite the fact, that if
the literal is being assigned somewhere they can be inferred from the
assignee's type.

The best way to avoid this is making the delegate take 0 arguments, in
which case the whole thing can be reduced to a single expression via a
lazy parameter.
The second best way (when lazy parameters are not accessible) is to
wrap the expression into a single return-statement in braces.
But that's as good as it can get with readability. Adding parameters
is a huge pain particularly because often you really don't want to
specify their types and storage classes, since those are known from
the type of variable, that is being initialized by the literal.

I just looked up Wikipedia for lambdas in different languages and
found out, that C# has an awesome syntax for that:

x =3D> x * x
(x, y) =3D> x =3D=3D y
(int x, string s) =3D> s.Length > x
() =3D> SomeMethod()
n =3D> { string s =3D n + " " + "World"; Console.WriteLine(s); }

The fat arrow operator (=3D>) isn't used in D and cannot be confused
with anything (there's no way to write that and not get an error).
The fat arrow operator looks confusing (especially with equality
operators in the lambda's body), so the arrow operator (->) can be
used instead (which is also unused and unambiguous).
Specifying the literal type is easily accomplished by adding the
appropriate keyword in front of the expression (as it's done now).
The only remaining problem are the keywords being too long, which is
not gonna change, since even adding new keywords is a breaking change.
In the future, though, it would be great to shorten them to something
like "fn" and "dg" or something.
Nonetheless, this would be a great-looking D code:

alias int function(int, int) Fn;
alias int delegate(int, int) Dg;

Fn a0 =3D function (a, b) -> a + b;
Dg a1 =3D delegate (a, b) -> a + b;
Dg a2 =3D (c, f) -> a + b;

On Thu, Oct 6, 2011 at 7:32 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Thu, 06 Oct 2011 10:56:43 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 Hi, guys.

 I just made my handy parsing struct take an arbitrary range, instead
 of a dstring and immediately rain head-first into a brick wall of
 errors.

 There's this function:
 =A0 =A0bool next(bool function(ElementType!InputType) pred)

 , where InputType is bound to be dstring and which gets called like this=


 =A0 =A0parser.next(&isAlpha)

 , where isAlpha is from std.uni.
 When i do that, i get this error:
 =A0 =A0Error: cannot implicitly convert expression (& isAlpha) of type
 bool function(dchar c) pure nothrow  safe to bool
 function(immutable(dchar))

 Yes, I understand why do i get this error.
 What i don't understand is: does the dchar being immutable really
 change anything?

What it does is make it so during the function, the parameter cannot be changed. =A0It technically has no effect on what you can pass to the func=

 since as you rightly point out, ints implicitly cast between const,
 immutable, and mutable.

 Why did someone do it? =A0To ensure they didn't accidentally write code t=

 changed the value inside the function. =A0The compiler might also use tha=

 information to do some optimization (i.e. avoid reloading into a register=

 but I doubt it's necessary for that.

 To answer your underlying question, why doesn't the delegate "just work"?
 It's because D does not allow implicit casting of delegates or functions =

 all. =A0I assume this will get better at some point, because implicit cas=

 of delegates would make things just so much smoother in generic programmi=

 -Steve

Oct 06 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan  
<gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). In fact, nobody actually wrote the immutable(dchar) function, it's just that the element type is immutable(dchar). However, the reasons why someone would want to create a function that takes an immutable(dchar) function are as I stated -- so you don't accidentally change the value. Still no excuse that delegates cannot be implicitly cast to compatible versions.
 I just looked up Wikipedia for lambdas in different languages and
 found out, that C# has an awesome syntax for that:

 x => x * x
 (x, y) => x == y
 (int x, string s) => s.Length > x
 () => SomeMethod()
 n => { string s = n + " " + "World"; Console.WriteLine(s); }

In the not so distant past, Walter explored different ways to improve the lambda syntax on this news group (which included similarities to the above). This usually means he is considering adding that change, let's hope so :) -Steve
Oct 06 2011
prev sibling next sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
Also, this would be a whole lot easier if D got a full built-in tuple
support, because then all functions would always take a single
argument. :-)

On Thu, Oct 6, 2011 at 10:56 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). =A0In fact, nobody actually w=

 the immutable(dchar) function, it's just that the element type is
 immutable(dchar). =A0However, the reasons why someone would want to creat=

 function that takes an immutable(dchar) function are as I stated -- so yo=

 don't accidentally change the value.

 Still no excuse that delegates cannot be implicitly cast to compatible
 versions.

 I just looked up Wikipedia for lambdas in different languages and
 found out, that C# has an awesome syntax for that:

 x =3D> x * x
 (x, y) =3D> x =3D=3D y
 (int x, string s) =3D> s.Length > x
 () =3D> SomeMethod()
 n =3D> { string s =3D n + " " + "World"; Console.WriteLine(s); }

In the not so distant past, Walter explored different ways to improve the lambda syntax on this news group (which included similarities to the abov=

 =A0This usually means he is considering adding that change, let's hope so=

 -Steve

Oct 09 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 10 Oct 2011 21:29:08 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 10/10/11 5:55 PM, Don wrote:
 On 06.10.2011 20:56, Steven Schveighoffer wrote:
 On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). In fact, nobody actually wrote the immutable(dchar) function, it's just that the element type is immutable(dchar). However, the reasons why someone would want to create a function that takes an immutable(dchar) function are as I stated -- so you don't accidentally change the value.

That seems like the discussed-and-discarded 'final' storage class for parameters. But this is worse. It has an *enormous* cost.

Walter and I have agreed for a long time that upon function calls with by-value passing, there should be some simple transforms done: 1. If a parameter has no indirections, qual(T) becomes T. 2. qual(T[]) becomes qual(T)[]. 3. qual(T*) becomes qual(T)*. This would improve many aspects of the language. Walter never got to implementing it, but I'm bringing this up in case one of the wonderful compiler contributors would want to take it up. Again, I have reasons to believe Walter would approve of the change.

I agree, this would help tremendously. Would this apply to function pointers/delegates as well? For example: void foo(const(int) i) {} assert(is(typeof(&foo) == void function(int)); I would prefer it not be this way, and rather start defining some implicit delegate/function casting. I think D really needs this, not just in the area of const. -Steve
Oct 11 2011
prev sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
assert(is(typeof(&foo) : void function(int));

On Tue, Oct 11, 2011 at 6:35 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Mon, 10 Oct 2011 21:29:08 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 10/10/11 5:55 PM, Don wrote:
 On 06.10.2011 20:56, Steven Schveighoffer wrote:
 On Thu, 06 Oct 2011 12:27:16 -0400, Gor Gyolchanyan
 <gor.f.gyolchanyan gmail.com> wrote:

 I see. Thanks for the detailed answer.

I should clarify one point, I realized I am somewhat inaccurate on the reason the type is set to immutable(dchar). In fact, nobody actually wrote the immutable(dchar) function, it's just that the element type i=




 immutable(dchar). However, the reasons why someone would want to creat=




 a function that takes an immutable(dchar) function are as I stated -- =




 you don't accidentally change the value.

That seems like the discussed-and-discarded 'final' storage class for parameters. But this is worse. It has an *enormous* cost.

Walter and I have agreed for a long time that upon function calls with by-value passing, there should be some simple transforms done: 1. If a parameter has no indirections, qual(T) becomes T. 2. qual(T[]) becomes qual(T)[]. 3. qual(T*) becomes qual(T)*. This would improve many aspects of the language. Walter never got to implementing it, but I'm bringing this up in case one of the wonderful compiler contributors would want to take it up. Again, I have reasons to believe Walter would approve of the change.

I agree, this would help tremendously. Would this apply to function pointers/delegates as well? =A0For example: void foo(const(int) i) {} assert(is(typeof(&foo) =3D=3D void function(int)); I would prefer it not be this way, and rather start defining some implici=

 delegate/function casting. =A0I think D really needs this, not just in th=

 area of const.

 -Steve

Oct 11 2011