alias this
Subtyping with 'alias this' is superb and easy; it's a tremendous simplifying mechanism, one of D's many ingenious and well integrated technical simplifying mechanisms that were a big part of getting me on board, spreading the word and moving to D. What is the design logic behind 364.d(9): Error: alias this compileme364.number.__anonymous there can be only one alias this --- not a complaint, I'd just like to hear opinion of the basis of the above restriction from experts.
Re: alias this
On Thu, 30 Aug 2012 07:48:54 -0400, Carl Sturtivant wrote: Subtyping with 'alias this' is superb and easy; it's a tremendous simplifying mechanism, one of D's many ingenious and well integrated technical simplifying mechanisms that were a big part of getting me on board, spreading the word and moving to D. What is the design logic behind 364.d(9): Error: alias this compileme364.number.__anonymous there can be only one alias this --- not a complaint, I'd just like to hear opinion of the basis of the above restriction from experts. This is a limitation in implementation. According to TDPL, there will be multiple alias this allowed in the final implementation. See this bug: http://d.puremagic.com/issues/show_bug.cgi?id=6083 -Steve
Re: alias this
On Thursday, 30 August 2012 at 12:58:28 UTC, Steven Schveighoffer wrote: On Thu, 30 Aug 2012 07:48:54 -0400, Carl Sturtivant wrote: Subtyping with 'alias this' is superb and easy; it's a tremendous simplifying mechanism, one of D's many ingenious and well integrated technical simplifying mechanisms that were a big part of getting me on board, spreading the word and moving to D. What is the design logic behind 364.d(9): Error: alias this compileme364.number.__anonymous there can be only one alias this --- not a complaint, I'd just like to hear opinion of the basis of the above restriction from experts. This is a limitation in implementation. According to TDPL, there will be multiple alias this allowed in the final implementation. See this bug: http://d.puremagic.com/issues/show_bug.cgi?id=6083 -Steve Ah, thanks. Glad to hear the eventual outcome is broad.
Re: alias this
What is the design logic behind 364.d(9): Error: alias this compileme364.number.__anonymous there can be only one alias this --- not a complaint, I'd just like to hear opinion of the basis of the above restriction from experts. This is a limitation in implementation. According to TDPL, there will be multiple alias this allowed in the final implementation. See this bug: http://d.puremagic.com/issues/show_bug.cgi?id=6083 Perhaps you can point me at a way to get a short list of features like this that we might say are "strategically limited" at the moment (perhaps even to the extent of being absent even), but definitely intended for complete implementation eventually.
Re: alias this
On 01/09/12 15:16, Carl Sturtivant wrote: What is the design logic behind 364.d(9): Error: alias this compileme364.number.__anonymous there can be only one alias this --- not a complaint, I'd just like to hear opinion of the basis of the above restriction from experts. This is a limitation in implementation. According to TDPL, there will be multiple alias this allowed in the final implementation. See this bug: http://d.puremagic.com/issues/show_bug.cgi?id=6083 Perhaps you can point me at a way to get a short list of features like this that we might say are "strategically limited" at the moment (perhaps even to the extent of being absent even), but definitely intended for complete implementation eventually. http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel#Roadmap
alias this question
I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? O. module AliasThis; import S; import K; void foo(S s) { //... } void main() { const K k; foo(k); }module S; struct S { int x; }module K; import S; struct K { S s; public alias s this; }
alias this constructor
struct Foo { int x; alias x this; } Foo f = 12; // error Foo foo; f = 12; // this is OK any reason why the first cant be allowed?
multiple alias this
An implementation method: Single `alias this` already works, this method leverages it to create a multiple `alias this`. This method is presented for a basic review 1. alias a,b,... this; Is this proposed syntax used for assigning multiple sinks for the dispatching of access '.' operator. It is also called an `alias this` with multiple implicit for the case of one alias. struct X { int a; string s; alias a,s this } X x; void foo(T)(T x); 2. Here the compiler chooses which alias works by inference. foo(x) fails because of ambiguity in that it accepts both aliases. The proposed rule is that that an `alias this` must resolve to one and only one alias. This rule allows the original single `alias this` algorithm to work for multiple `alias this` by effectively adding a loop in the testing section of the code(we test for each alias and if only one is successful then success, else failure) This rule prevents such things as struct X { int a; int b; double c; string s; alias a,b,c,s this } because b and a are the same type and both will resolve the inferencing rule giving at least 2 variables rather than the one required by the rule. c and s may or may not fail depending on context. The simplification here is that no other code anywhere dealing with the use of multiple `alias this` needs to be modified such as templates, traits, runtime, etc. If the single alias this code that determines if the alias is active is represented by SA!(T,typeof(aliasthis)) which returns true if the type of the single `alias this` is T, the parameter or object "returned", then multiple `alias this` looks something like int count = 0; foreach(ma; multiplealiasthislist) count += (SA!(T,typeof(aliasthis))) ? 1 : 0; if (count != 1) error(); when the single `alias this` code would look like if (!SA!(T,typeof(aliasthis))) error(); For `.` access each type is checked in the loop in a similar manner for only one solution. 3. Why this works is because for orthogonal types we'ed expect no issues and that generally will be the case. Therefore we simply limit multiple `alias this` to the case where all the types are orthogonal. (convenient way to solve the problem, but orthogonality is easily defined in D) For non-orthogonal types we just error out and let the programmer figure out the proper solution. D can attempt to check if all the types are orthogonal at compile time in two ways. Either at the declaration of the alias this or at the resolving point. If it is done at resolution then it relaxes orthogonality requirements by allowing some cases to pass simply because the context allows it but it could fail the resolve when the program has been modified. 4. e.g., for a 2-ply multiple `alias this` we have something like X given above. x and s are not orthogonal in all cases, specially with templates and so either the compiler can fail when parsing X or it can wait to test which types work in which circumstances and fail only if there is an ambiguity. The last way is the way D generally works as it offers a more relaxed error checking which allows many cases to work while also allowing for a more slightly brittle programming experience(which may not effect most people). 5. Templates are a special problem since they can accept any possible type, and a multiple alias this effectively is a multiple type. One can instantiate the template on all versions and if only one passes then that version is used, but this is prone to errors since what the programmer may think is the passed alias is not, and some corner cases it would be a difficult bug to detect. 6. reflection/traits should allow getting the multiple alias types and variable names.
Multiple Alias This
Is the limitation that one may only have one alias this per class/struct a temporary limitation that will be removed once higher-priority stuff is finished and some ambiguities are resolved, or are things likely to stay this way? On the one hand, allowing multiple alias this would cause ambiguities similar to multiple inheritance. On the other hand, only being able to define one implicit cast per class/struct is pretty limiting and allowing only one alias this seems like a huge cop-out.
Alias this and std.traits.isArray
This code worked with dmd 2.060: import std.stdio; import std.traits; struct OhWhy(S) { S[] arr; alias arr this; } void main() { static assert(isArray!(OhWhy!(float))); } But fails with dmd 2.061: ss.d(10): Error: static assert (isArray!(OhWhy!(float))) is false (same happens with alias this to static arrays and isArray/isStaticArray) Is this intended or a regression? If latter, I'll submit a bug-ticket.
Re: alias this question
Olli Aalto wrote: I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? This is intended. alias this (and any other alias) act as simple rewrites to the aliased symbol, and does not change their protection level. I believe there is a bug on this specific issue already, and #4533[1] certainly does describe it in general. http://d.puremagic.com/issues/show_bug.cgi?id=4533 -- Simen
Re: alias this question
On 13.2.2011 19:40, Simen kjaeraas wrote: Olli Aalto wrote: I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? This is intended. alias this (and any other alias) act as simple rewrites to the aliased symbol, and does not change their protection level. Pity. Would have been nice, now it's just one pretty useless feature at the end of a list of features for the language. O.
Re: alias this question
On 02/13/2011 05:30 PM, Olli Aalto wrote: I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? Dunno, lets me wonder: what are use cases of alias this on a public member? I mean, on a member that /must/ remain private. Then, it's just syntactic sugar, which is good, but why wrap it into an object? In my mind, the typical use case is precisely a wrapper struct around something that, so-to-say, "naturally" ends up private. Denis -- _ vita es estrany spir.wikidot.com
Re: alias this question
On 02/13/11 10:30, Olli Aalto wrote: > I encountered a problem with alias this, when the aliased member is > private. I'm using the latest dmd2. It reports the follwing: > src\main.d(14): Error: struct K.K member s is not accessible > > If I change the private modifier on the s member to public it works. > > Is this as intended, or a bug? > > O. > There is actually an alternative, but I believe I remember it being said that this would go away. In the meantime, I think it still works and maybe it could be saved. The alternative is to define a method opDot() which returns the entity to forward the call to. Check out std.typecons:Unique for an example. -- Chris N-S
Re: alias this question
On 2011-02-16 20:42, Christopher Nicholson-Sauls wrote: On 02/13/11 10:30, Olli Aalto wrote: I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? O. There is actually an alternative, but I believe I remember it being said that this would go away. In the meantime, I think it still works and maybe it could be saved. The alternative is to define a method opDot() which returns the entity to forward the call to. Check out std.typecons:Unique for an example. -- Chris N-S Isn't opDot deprecated in favor of opDispatch? -- /Jacob Carlborg
Re: alias this question
On 02/17/2011 11:41 AM, Jacob Carlborg wrote: On 2011-02-16 20:42, Christopher Nicholson-Sauls wrote: On 02/13/11 10:30, Olli Aalto wrote: I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? O. There is actually an alternative, but I believe I remember it being said that this would go away. In the meantime, I think it still works and maybe it could be saved. The alternative is to define a method opDot() which returns the entity to forward the call to. Check out std.typecons:Unique for an example. -- Chris N-S Isn't opDot deprecated in favor of opDispatch? I personly need opDot, to customize member access ; not (only) method call. Denis -- _ vita es estrany spir.wikidot.com
Re: alias this question
On 2011-02-17 11:54, spir wrote: On 02/17/2011 11:41 AM, Jacob Carlborg wrote: On 2011-02-16 20:42, Christopher Nicholson-Sauls wrote: On 02/13/11 10:30, Olli Aalto wrote: I encountered a problem with alias this, when the aliased member is private. I'm using the latest dmd2. It reports the follwing: src\main.d(14): Error: struct K.K member s is not accessible If I change the private modifier on the s member to public it works. Is this as intended, or a bug? O. There is actually an alternative, but I believe I remember it being said that this would go away. In the meantime, I think it still works and maybe it could be saved. The alternative is to define a method opDot() which returns the entity to forward the call to. Check out std.typecons:Unique for an example. -- Chris N-S Isn't opDot deprecated in favor of opDispatch? I personly need opDot, to customize member access ; not (only) method call. Denis I'm pretty sure that you can use the getter/setter syntax with opDispatch, anything else is a bug. -- /Jacob Carlborg
Re: alias this question
Jacob Carlborg wrote: I'm pretty sure that you can use the getter/setter syntax with opDispatch, anything else is a bug. You can only use one of the two, and yes, the bug is already filed. -- Simen
alias 'this' with opCall?
Why doesn't opCall() get forwarded by alias this? Is that a bug or a feature?
DIP66 - Multiple alias this
I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it.
Multiple alias this redux
Following the approval of his DIP66, Igor Stepanov proceeded with an implementation at https://github.com/D-Programming-Language/dmd/pull/3998. Walter and I objected that the implementation is overly complex. My opinion is much weaker than his; I'm not deeply familiar with the dmd internals. Iain Buclaw seems to agree with Walter. and Igor has replied with additional explanations for the added complexity. As a result: * We have no alias this * The compiler is 2 KLOC smaller/simpler * The PR has bitrotten * Igor is probably frustrated So this is a stalemate that I'd like to see broken. The best solution I see with this is a core compiler contributor reviewing Igor's code and either: (a) Assuming Igor is still interested, give concrete, actionable guidance to Igor so he can simplify the PR and follow through shepherding the PR into dmd; (b) If Igor is no longer interested, either take over the PR and modify it for approval, or implement DIP66 from first principles; (c) Review the code and discussion, and reach the conclusion the proposed implementation is appropriate and no radical simplifications are within reach. Please chime in if you'd like to take this over. Thanks, Andrei
UFCS overrides alias this
test.d struct A{ string b; alias b this; } struct MyRange{ } char front(MyRange); void popFront(ref MyRange); bool empty(MyRange); void test(A a){ a.empty; } $ dmd -o- test test.d(14): Error: function test.empty (MyRange) is not callable using argument types (A) Is this intended behavior?
Re: alias this constructor
On Sunday, March 25, 2018 00:47:20 Dave Jones via Digitalmars-d wrote: > struct Foo > { > int x; > alias x this; > } > > Foo f = 12; // error > > Foo foo; > f = 12; // this is OK > > any reason why the first cant be allowed? Because it was deemed to cause too many problems. C++ code can have quite a few problems related to all of the implicit conversions it allows with stuff like constructing objects. Walter decided that D would be better off if it did not allow such conversions, and as such, D is much pickier about implicit conversions in general. Occasionally, the restrictions are annoying, but they also prevent bugs. I have no idea whether Walter could be convinced at this point to allow some sort of implicit construction in D or not. Personally, I tend to think that we'd be better off if we didn't have alias this at all, because it tends to cause problems in anything outside of simple use cases (especially with generic code - implicit conversions in generic code are almost always a terrible idea). Sometimes, it's useful, but it's often just a recipe for subtle bugs. But at least the fact that D only allows you to implicitly convert in one direction reduces the problem. - Jonathan M Davis
Re: alias this constructor
On Sunday, 25 March 2018 at 00:47:20 UTC, Dave Jones wrote: struct Foo { int x; alias x this; } Foo f = 12; // error You just need to define a constructor that takes an int. alias this is all about taking an existing object and substituting a member for it - emphasis on *existing* object, so it needs to already be constructed. But you can construct from other types struct Foo { int x; this(int x) { this.x = x; } } Foo f = 12; // allowed, calls that constructor Foo foo; f = 12; // this is OK Important to note that foo already exists here and is NOT reconstructed - the compiler just rewrites that into `f.x = 12;`, doing a member assignment.
Re: alias this constructor
On 25/03/18 04:51, Jonathan M Davis wrote: On Sunday, March 25, 2018 00:47:20 Dave Jones via Digitalmars-d wrote: struct Foo { int x; alias x this; } Foo f = 12; // error Foo foo; f = 12; // this is OK any reason why the first cant be allowed? Because it was deemed to cause too many problems. C++ code can have quite a few problems related to all of the implicit conversions it allows with stuff like constructing objects. Walter decided that D would be better off if it did not allow such conversions, and as such, D is much pickier about implicit conversions in general. That's a good reason to disallow assignment from int to Foo. I see zero sense in allowing assignment and disallowing construction. * Technically, I understand the mechanisms at play here. During construction, this is a Foo object, and it has no construction from int. During assignment, we are allowed to convert a Foo lvalue to a Foo.x (int) lvalue, and that gets assigned. Despite understanding the mechanics, I find the end result surprising and unexpected. D makes it damn easy to implicitly expose an inner member, and much more difficult to actually do this safely (you have to create a property and then alias this that property). If I'd be building C++ today, I'd replace the "explicit" keyword with "implicit" (i.e. - still allow single var constructors to become implicit conversion ops, but make that transformation an opt-in rather than an opt-out feature). I think that would have been a much better approach than what D took. Shachar
Re: alias this constructor
On Sunday, March 25, 2018 06:24:35 Shachar Shemesh via Digitalmars-d wrote: > On 25/03/18 04:51, Jonathan M Davis wrote: > > On Sunday, March 25, 2018 00:47:20 Dave Jones via Digitalmars-d wrote: > >> struct Foo > >> { > >> > >> int x; > >> alias x this; > >> > >> } > >> > >> Foo f = 12; // error > >> > >> Foo foo; > >> f = 12; // this is OK > >> > >> any reason why the first cant be allowed? > > > > Because it was deemed to cause too many problems. C++ code can have > > quite a few problems related to all of the implicit conversions it > > allows with stuff like constructing objects. Walter decided that D > > would be better off if it did not allow such conversions, and as such, > > D is much pickier about implicit conversions in general. > > That's a good reason to disallow assignment from int to Foo. I see zero > sense in allowing assignment and disallowing construction. > > * > > Technically, I understand the mechanisms at play here. During > construction, this is a Foo object, and it has no construction from int. > During assignment, we are allowed to convert a Foo lvalue to a Foo.x > (int) lvalue, and that gets assigned. > > Despite understanding the mechanics, I find the end result surprising > and unexpected. D makes it damn easy to implicitly expose an inner > member, and much more difficult to actually do this safely (you have to > create a property and then alias this that property). Having something like opImplicitCast would arguably have been better than alias this. > If I'd be building C++ today, I'd replace the "explicit" keyword with > "implicit" (i.e. - still allow single var constructors to become > implicit conversion ops, but make that transformation an opt-in rather > than an opt-out feature). I think that would have been a much better > approach than what D took. That would be a significant improvement for C++, though over time, I've increasingly become of the opinion that adding implicit conversions to user-defined types is more trouble than it's worth. There are certainly times when it's useful, but it causes enough problems that I'm not at all convinced that it's ultimately a feature worth having. And with the route that D went, implicit conversions are arguably crippled anyway. So, we have a partial solution that isn't really enough to cleanly use implicit conversions when it might be appropriate, but what we have is still enough to cause problems. - Jonathan M Davis
opDispatch and alias this
Apparently three years ago it was we decided to ban alias this and opDispatch in the same class. What are your thoughts on this now? Is anyone depending on using alias this + opDispatch together like e.g. in https://github.com/dlang/phobos/pull/6596?
Re: multiple alias this
On Friday, 20 July 2018 at 00:26:43 UTC, Mr.Bingo wrote: [...] I didn't read through all of that, but just so you are aware, a *multiple alias this* DIP was already approved. You can find it at https://wiki.dlang.org/DIP66 The implementation is already started and you can find it at https://github.com/dlang/dmd/pull/8378, but it's a big PR and reviewers are going to need time and effort to understand and analyze it. I hope it will be merged this release cycle, but that's just my optimism talking. Mike
alias this on module
Any reason why "alias this" doesn't work at the module level? If I recall correctly, a module is really just a "class" under the hood, but when I tried to use it I got: Error: alias this can only be a member of aggregate, not module
Alias this and inheritance
The following code does not compile: void foo(string a) {} class Base { alias bar this; string bar() { return ""; } } class Sub : Base {} void main() { auto sub = new Sub; foo(sub); } But if the "alias this" is copied/moved to the subclass it works. Is this expected behavior? -- /Jacob Carlborg
alias this and shadowing
I think the following example is legitimate code that should work: struct S1 { void foo() { writeln("S1.foo()"); } void foo(ulong x) { writefln("S1.foo(%d)", x); } } struct S2 { S1 s; alias s this; void foo(string str) { writeln("S2.foo(%s)", str); } } void main() { S2 s; s.foo("hahaha"); s.foo(100); // XXX this doesn't compile, since there's no S2.foo that accepts an int } To quote Andrei, if it looks like it should work, it should. (Also something about turtles). My original code did something a bit different, just to show another example of why this behavior looks fundamentally broken to me: struct S2 { S1 s; alias s this; @disable void foo(ulong); // calling foo(ulong) doesn't make sense in the context of S2 } Now, calling S2.foo() won't compile, since S2 only knows one prototype for foo which accepts a ulong.
"Multiple alias this" status?
Hi All, I just started to learn a little bit of D. I read this thread https://github.com/dlang/dmd/pull/3998 about "Multiple alias this". I think this feature is very handy, but dmd and gcd compilers complain that "there must be only one" alias this. It is not clear to me if this feature is not available yet or if there was a change in the language specifications (Andrei Alexandrescu book mentions "§6.13 Multiple subtyping") ? Does anyone has more information concerning that? Thanks in advance, Vincent
multiple `alias this` suggestion
Currently only one `alias this` declaration is permitted, and the documentation https://dlang.org/spec/class.html#AliasThis says the following. "Multiple AliasThis are allowed. For implicit conversions and forwarded lookups, all AliasThis declarations are attempted; if more than one AliasThis is eligible, the ambiguity is disallowed by raising an error. Note: Multiple AliasThis is currently unimplemented." However the effect of multiple `alias this` declarations can be approximated in existing D using only single `alias this`, e.g. in the following three members each with `alias this` are simulated. // struct member1 { int n1, n2, n3; } struct member2 { int n2, n3; member1 member; alias member this; } struct member3 { int n3; member2 member; alias member this; } struct top { member3 member; alias member this; this(int i, int j, int k) { n1 = i; n2 = j; n3 = k; } } void main() { auto x = top(1,2,3); member3 m3 = x.member; member2 m2 = m3.member; member1 m1 = m2.member; import std.stdio; writefln("%s %s %s", m1.n1, m1.n2, m1.n3); writefln("%s %s %s", m2.n1, m2.n2, m2.n3); writefln("%s %s %s", m3.n1, m3.n2, m3.n3); writefln("%s %s %s", x.n1, x.n2, x.n3); } // Which outputs the following as expected from chaining the effects of `alias this`. 1 0 0 1 2 0 1 2 3 1 2 3 Note that this construction provides a natural hierarchy for name lookup, unlike the statement above taken from the documentation. Imagine the existing single `alias this` is extended to provide such a heierarchy of lookups. For example, struct top { mem3 m3; mem2 m2; mem1 m1; alias m3, m2, m1 this; // ... } could be interpreted to mean search for a name in m3 if not found in top, and in m2 if not found in m3 and in m1 if not found in m2. I don't back the syntax, just the notion. Maybe that's not all that's expected from "multiple alias this" but it would be a clean step forward. Issues?
Re: Multiple Alias This
dsimcha wrote: Is the limitation that one may only have one alias this per class/struct a temporary limitation that will be removed once higher-priority stuff is finished and some ambiguities are resolved, or are things likely to stay this way? On the one hand, allowing multiple alias this would cause ambiguities similar to multiple inheritance. On the other hand, only being able to define one implicit cast per class/struct is pretty limiting and allowing only one alias this seems like a huge cop-out. Yah, it's a temporary limitation. However, removing it is nontrivial. D tries to avoid first-fit rules and best-fit is difficult. Note that if you have control over the types you can implement a sort of a first-fit by distributing the "alias this" declaration to each type. (This is very clumsy.) Andrei
Re: Doubt about alias this
Hi, I tested the code you provided and extended it a little and here is the result: struct bar (bool B, N...) { int n = 0; } struct foo (N...) { bar!(true, N) _bar = void; bar!(true, N) getN() { return _bar; } alias getN this; public this(T) (T other) if (is(T unused : int)) { n = other; } } void aFunc( bar!( true, 8 ) zeBar ) { //Subtyping compiles. } bar!( true, 8 ) aSecondFunc() { return bar!( true, 8 )(); } struct toto{ size_t payload; } toto aThirdFunc() { return toto(); } void main() { import std.stdio; foo!8 a = 42; writeln(a.n); //Prints 0, as it should. aFunc( a ); //The alias this correctly allows for subtyping, as advertised a.getN().n = 3; //Allowing for rvalue manipulation is indeed weird, but apparently in a coherent fashion, not just for the alias this case. writeln(a.n); //Still prints 0, as it should. aSecondFunc().n = 4; aThirdFunc().payload = 10; //Without alias this, without templates, juste plain rvalue. Another coherent example, yet questionably permitted. } Therefore, your question, I believe, is more related to rvalues directly rather than alias this, if I get your meaning right. The question is still very relevant and I was surprised to find out about the current behaviors of rvalues.
Re: Alias this and std.traits.isArray
On Saturday, 5 January 2013 at 14:43:49 UTC, David wrote: This code worked with dmd 2.060: import std.stdio; import std.traits; struct OhWhy(S) { S[] arr; alias arr this; } void main() { static assert(isArray!(OhWhy!(float))); } But fails with dmd 2.061: ss.d(10): Error: static assert (isArray!(OhWhy!(float))) is false (same happens with alias this to static arrays and isArray/isStaticArray) Is this intended or a regression? If latter, I'll submit a bug-ticket. All traits in std trait of the type were explicitly changed to return true only if *the exact type* meets the traits requirement. The rationale is simply tha OhWhy isn't an array. It can be implicitly cast to array, but it isn't an array. This is problematic when instanciating template functions with automatic type inference: when you write "myTemplateFunction(myOhWhy)", then you will instanciate "myTemplateFuction!OhWhy" when what you may have wanted was to actually call "myTemplateFunction!(S[])". The new "isArray" definition protects from that.
Re: Alias this and std.traits.isArray
On Saturday, January 05, 2013 22:57:51 monarch_dodra wrote: > On Saturday, 5 January 2013 at 14:43:49 UTC, David wrote: > > This code worked with dmd 2.060: > > > > import std.stdio; > > import std.traits; > > > > struct OhWhy(S) { > > > > S[] arr; > > alias arr this; > > > > } > > > > void main() { > > > > static assert(isArray!(OhWhy!(float))); > > > > } > > > > But fails with dmd 2.061: > > ss.d(10): Error: static assert (isArray!(OhWhy!(float))) is > > false > > > > (same happens with alias this to static arrays and > > isArray/isStaticArray) > > > > > > Is this intended or a regression? If latter, I'll submit a > > bug-ticket. > > All traits in std trait of the type were explicitly changed to > return true only if *the exact type* meets the traits requirement. > > The rationale is simply tha OhWhy isn't an array. It can be > implicitly cast to array, but it isn't an array. > > This is problematic when instanciating template functions with > automatic type inference: when you write > "myTemplateFunction(myOhWhy)", then you will instanciate > "myTemplateFuction!OhWhy" when what you may have wanted was to > actually call "myTemplateFunction!(S[])". > > The new "isArray" definition protects from that. Exactly. The std.traits traits are testing for exact types. If you want to test for implicit conversion, then use the : operator. e.g. static assert(is(OhWhy!float : float[])); - Jonathan M Davis
Re: Alias this and std.traits.isArray
Thanks for your answers, but: > Exactly. The std.traits traits are testing for exact types. If you want to > test for implicit conversion, then use the : operator. e.g. > > static assert(is(OhWhy!float : float[])); "OyWhy" is a templated struct for a reason, I have no idea which type of array is "alias this'ed" is there a way I can check if it's implicitly convertable to any array type with some `is` magic I am not aware of?
Re: Alias this and std.traits.isArray
On Sun, Jan 6, 2013 at 1:36 PM, David wrote: > Thanks for your answers, but: > > > Exactly. The std.traits traits are testing for exact types. If you want > to > > test for implicit conversion, then use the : operator. e.g. > > > > static assert(is(OhWhy!float : float[])); > > "OyWhy" is a templated struct for a reason, I have no idea which type of > array is "alias this'ed" is there a way I can check if it's implicitly > convertable to any array type with some `is` magic I am not aware of? > > Like this? struct MyType(Elem) { Elem[] inner; alias inner this; } void main() { static assert(is(MyType!float _ : T[], T)); }
Re: Alias this and std.traits.isArray
> Like this? > > struct MyType(Elem) > { > Elem[] inner; > alias inner this; > } > > void main() > { > static assert(is(MyType!float _ : T[], T)); > } > And how does that work for a static array?
Re: Alias this and std.traits.isArray
On Wed, Jan 9, 2013 at 10:57 PM, David wrote: >> Like this? >> >> struct MyType(Elem) >> { >> Elem[] inner; >> alias inner this; >> } >> >> void main() >> { >> static assert(is(MyType!float _ : T[], T)); >> } >> > > And how does that work for a static array? For a static array, the generic type is T[n], for some T and a size_t n. So: static assert(is(MyType!float _ : T[n], T, size_t n));
Behaviour of alias this changed
I have some code along these lines: struct S { short[4] data; alias this data; string toString() { ... } } ... S s; writeln(to!string(s)); In dmd 2.059 (I believe) and earlier, this calls S.toString(). However, in git dmd, this calls data.toString() instead. I'm just curious about the rationale for this change, and whether there's a way to override the toString() call so that it always calls S.toString()? T -- To err is human; to forgive is not our policy. -- Samuel Adler
Re: alias 'this' with opCall?
On Thu, May 17, 2012 at 08:06:58PM +0200, Mehrdad wrote: > Why doesn't opCall() get forwarded by alias this? Is that a bug or a > feature? Sounds like a bug. T -- The peace of mind---from knowing that viruses which exploit Microsoft system vulnerabilities cannot touch Linux---is priceless. -- Frustrated system administrator.
Re: alias 'this' with opCall?
okie. http://d.puremagic.com/issues/show_bug.cgi?id=8113
alias this and immutable shenanigans
Consider this code: --- module test; struct Foo { this( int f ) { _foo = f; } @property int baz() { return _foo; } // alias _foo this; // alias baz this; immutable int _foo; } struct Bar { this( int f ) { _foo = Foo(f); } private: immutable Foo _foo; } --- If I uncomment the alias _foo this line, I get the following error message: % Test.d(22): Error: can only initialize const member _foo inside constructor WTF! I'm initializing it in a constructor! Is this a bug? Or by design you cannot alias this to a immutable member of a struct. It seems that there's a hidden temp created that wants to initialize the field. Also, I wanted to alias the property Foo.baz, but it also caused the following errors: % Test.d(22): Error: function test.Foo.baz () is not callable using argument types (Foo) immutable % Test.d(22): Error: expected 0 arguments, not 1 for non-variadic function type @property int() It seems that somehow the property is used as a "setter", not as a "getter". So, my questions are: 1. Why is disallowed to alias this an immutable data inside a struct? 2. Why is disallowed to alias this a struct "getter" property? -- Yao G.
bug? alias this <-> opDispatch interaction
I'm experimenting with several designs and I think I might have hit a bug, but I wanted to confirm it. Is this a bug? class A { void opDispatch(string name, T...)(T msg) {} } class B : A { C obj; alias obj this; @disable void opDispatch(string name, T...)(T msg); } class C { void foo() {} } void main() { auto b = new B; b.foo(); } Output: Error: no property 'foo' for type 'B' Disabling the opDispatch that B inherits from A also seems to disable B's alias this to C. The @disable works well in isolation -- as does the alias this, of course. My current workaround: class B : A { C obj; void opDispatch(string name, T...)(T msg) { mixin("obj." ~ name ~ "();"); } } (which now makes me wonder what actually are the differences between those two...) BTW, I was asking in the IRC channel (I should have discovered that lovely place earlier!) about the following: 1:T[string] foo; 2:foo[""] = new T; 3:foo[null] = new T; Lines 2 and 3 seem to do the same, apparently. People seemed to agree that 3 should not be relied upon (should it?), but if I recall/understand it was not totally clear to people why 2 and 3 *do* do the same thing, so feel free to clarify.
Re: DIP66 - Multiple alias this
On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." -Steve
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 17:31:23 UTC, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." -Steve TDPL tells that multiple alias this should be allowed, but tell nothing about conflict resolving. General idea of this DIP is sistematize rules for alias this. Please comment this part. Maybe I've forgot some cases, maybe introduce dangerous semantic rule.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 17:31:23 UTC, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." -Steve Igor was asked to write a DIP for it by Walter and Andrei. Here's the context: https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58286631
Re: DIP66 - Multiple alias this
On 10/10/14, 10:09 AM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Thanks, will do. Everybody interested please chime in! -- Andrei
Re: DIP66 - Multiple alias this
On 10/10/14, 10:31 AM, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." TDPL is not reference. The DIP should cover various corner cases. -- Andrei
Re: DIP66 - Multiple alias this
On 10/10/14 2:17 PM, Andrei Alexandrescu wrote: On 10/10/14, 10:31 AM, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." TDPL is not reference. The DIP should cover various corner cases. -- Andrei OK, thanks everyone. I thought DIPs were specifically for proposals that had not been already approved. -Steve
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. There is an error in the wiki formatting in the second code block. (`{| class="wikitable"` should not be there) I don't see any problems with the actual content of the DIP.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. I understand that as a first step it was suggested to implement the strictest behaviour regarding conflicts, namely to disallow them entirely. However, I think more permissive strategies are useful, like in this example: https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58570742 Conflict resolution can work like overload resolution, with different levels of matching and partial ordering.
Re: DIP66 - Multiple alias this
On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve
Re: DIP66 - Multiple alias this
On 10/10/2014 10:09 AM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. Thanks, Igor!
Re: DIP66 - Multiple alias this
Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve In this case, you will see the real error and will able to fix if. For example call foo(c.a); Otherwice, you possible error will be fixed without taking into account your opinions.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 20:29:43 UTC, Brian Schott wrote: On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. There is an error in the wiki formatting in the second code block. (`{| class="wikitable"` should not be there) I don't see any problems with the actual content of the DIP. Fixed. This is starnge implicit copy-paste of my text editor =/
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 20:47:45 UTC, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve I thought exactly about this using case. See: You have a struct like this in first place: struct A { int i; alias i this; } struct C { A a; string s; alias a this; alias s this; } And you have a template function in second place: void foo(T)(T t) if(is(T : int)) { ... } void foo(T)(T t) if(is(T : string)) { ... } And you have the code it third place: C c; foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : int) Now, someone (A developer) changed the A definition: struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B b; string s; alias a this; alias b this; alias s this; } And now, you code mystically start to works. Attention: Infusing in one place conflict resolves conflict in another place. It is danger, I think.
Re: DIP66 - Multiple alias this
On 10/10/14 5:15 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 20:47:45 UTC, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve I thought exactly about this using case. See: You have a struct like this in first place: struct A { int i; alias i this; } struct C { A a; string s; alias a this; alias s this; } And you have a template function in second place: void foo(T)(T t) if(is(T : int)) { ... } void foo(T)(T t) if(is(T : string)) { ... } And you have the code it third place: C c; foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : int) I agree with all this. Now, someone (A developer) changed the A definition: struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B b; string s; alias a this; alias b this; alias s this; } And now, you code mystically start to works. Why? It's just as confused as before, no? The way the DIP reads, the call to foo(c) compiles, but the instantiation fails. This can cause subtle issues when you want to select an instantiation based on what it casts to. An example: foo(T)(T t) if(is(T : int)) { someFuncThatTakesInt(t); } foo(T)(T t) if(!is(T : int) && is(T.shadow : int)) { someFuncThatTakesInt(t.shadow); } struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B shadow; alias a this; alias shadow this; } C c; foo(c); // should compile, but I think your DIP makes it fail due to ambiguity -Steve
Re: DIP66 - Multiple alias this
On 10/10/2014 10:09 AM, IgorStepanov wrote: Please, comment it. > static assert(is(C : int)); //Ok, because C is subtype of int anyway. Comment should say that C is implicitly convertible to int struct Test1 { int a; int b; alias a this; alias b this; //Error: alias b this conflicts with alias a this; } DIP says this is "obviously incorrect", but what rule is being applied? I suspect the rule here is if typeof(a)==typeof(b), then it is rejected. What if typeof(a) is implicitly convertible to typeof(b), and vice-versa? Is alias this resolved before base class search, after base class search, or is it an error if both searches are successful? If 'a' and 'b' both contain overloads for function foo, then it should behave like imports do (which is a bit complex). Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 20:44:11 UTC, Marc Schütz wrote: On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. I understand that as a first step it was suggested to implement the strictest behaviour regarding conflicts, namely to disallow them entirely. However, I think more permissive strategies are useful, like in this example: https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58570742 Conflict resolution can work like overload resolution, with different levels of matching and partial ordering. There isn't hard to change resolving strategy. This will need to change one function definition. Thus we able to implement strictest now and after some time of new feature using, relax the behaviour. This will not require significant efforts.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright wrote: On 10/10/2014 10:09 AM, IgorStepanov wrote: Please, comment it. > static assert(is(C : int)); //Ok, because C is subtype of int anyway. Comment should say that C is implicitly convertible to int Not really. int i = C(); //conflict: c.a.i vs c.b.i (thus, C is not implicitly convertible to int) struct Test1 { int a; int b; alias a this; alias b this; //Error: alias b this conflicts with alias a this; } DIP says this is "obviously incorrect", but what rule is being applied? I suspect the rule here is if typeof(a)==typeof(b), then it is rejected. What if typeof(a) is implicitly convertible to typeof(b), and vice-versa? In current state, if "typeof(a) is implicitly convertible to typeof(b), and vice-versa", compiler will accept this alias this declaration. However error may be raised at alias this resolving stage. Is alias this resolved before base class search, after base class search, or is it an error if both searches are successful? In existing alias this implementation alias this resolved after base class search. This DIP inherits it, thus now I suggest to check base classes before alias this. Is it acceptable? Should I add this into DIP? If 'a' and 'b' both contain overloads for function foo, then it should behave like imports do (which is a bit complex). Hmm. Now it works as I wrote it DIP pseudo-code: struct A { void foo(string); void foo(int); } struct B { void foo(double); } struct C { A a; B b; alias a this; alias b this; } C.foo("test"); //found only one acceptable foo: C.a.foo(string) C.foo(5); //1. Check a: found C.a.foo(int); //2. Check b: found C.b.foo(double); //3. Raise error: C.a.foo(int) vs C.b.foo(double) conflict C.foo(5.0);//found only one acceptable foo: C.b.foo(double) Is it Ok? Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected. Where can I read about multiple mixin templates?
Re: DIP66 - Multiple alias this
On 10/10/2014 11:25 PM, Walter Bright wrote: Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected. Agreed. Do you suggest to overload alias this against imports and mixin templates?
Re: DIP66 - Multiple alias this
On 10/10/2014 07:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. - "C c; int i = c; //Error: c.a.i vs c.b.i static assert(is(C : int)); //Ok, because C is subtype of int anyway." So now we can have 'subtypes' whose instances cannot be stored in variables of the 'base type'? Such behaviour is inconsistent with both the reference implementation and the documentation (and the two happen to be mutually inconsistent on how 'is(:)' should behave as well. :o) ) - "The following pseudo-code illustrates this: [...] Finally, if resultSet contains only one candidate, the compiler will accept it." This process might very well never terminate but it could terminate in more cases if it did something better than the naive brute-force search. I.e. either report cycles or don't keep exploring around cycles, but just looping indefinitely on cycles like the following is IMO not a good course of action: struct S{ alias get this; T get(){ return T.init; } } struct T{ alias get this; S get(){ return S.init; } int x; alias x this; } void main(){ S s; int x=s; } Furthermore, the following code compiles now, but doesn't under the approach described in the DIP. Is this an actual regression your pull introduces or is there a bug in the pseudocode?: class A{ alias x this; int x; } class B: A{ alias y this; int y; } void main(){ int x = new B(); } The same issue also needs to be considered if A and B are structs instead and B has an additional alias this to an A (the solution might also be part of a fix for the cycle issue). - "If resultSet contains more then one candidates, the compiler raises an error." Why? The language already has a way to deal with cross-scope overload resolution. (Also, what makes candidates different?)
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 21:26:49 UTC, Steven Schveighoffer wrote: On 10/10/14 5:15 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 20:47:45 UTC, Steven Schveighoffer wrote: On 10/10/14 1:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve I thought exactly about this using case. See: You have a struct like this in first place: struct A { int i; alias i this; } struct C { A a; string s; alias a this; alias s this; } And you have a template function in second place: void foo(T)(T t) if(is(T : int)) { ... } void foo(T)(T t) if(is(T : string)) { ... } And you have the code it third place: C c; foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : int) I agree with all this. Now, someone (A developer) changed the A definition: struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B b; string s; alias a this; alias b this; alias s this; } And now, you code mystically start to works. Why? It's just as confused as before, no? The way the DIP reads, the call to foo(c) compiles, but the instantiation fails. This can cause subtle issues when you want to select an instantiation based on what it casts to. An example: foo(T)(T t) if(is(T : int)) { someFuncThatTakesInt(t); } foo(T)(T t) if(!is(T : int) && is(T.shadow : int)) { someFuncThatTakesInt(t.shadow); } struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B shadow; alias a this; alias shadow this; } C c; foo(c); // should compile, but I think your DIP makes it fail due to ambiguity -Steve You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say
Re: DIP66 - Multiple alias this
On 10/11/2014 12:07 AM, IgorStepanov wrote: On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright wrote: If 'a' and 'b' both contain overloads for function foo, then it should behave like imports do (which is a bit complex). Hmm. Now it works as I wrote it DIP pseudo-code: The pseudo-code doesn't actually specify that the arguments the identifier is being called with are considered at all. struct A { void foo(string); void foo(int); } struct B { void foo(double); } struct C { A a; B b; alias a this; alias b this; } C.foo("test"); //found only one acceptable foo: C.a.foo(string) C.foo(5); //1. Check a: found C.a.foo(int); //2. Check b: found C.b.foo(double); //3. Raise error: C.a.foo(int) vs C.b.foo(double) conflict C.foo(5.0);//found only one acceptable foo: C.b.foo(double) Is it Ok? ... That is the right behaviour. What happens in this case: struct A{ void foo(int); void foo(double); } struct B void foo(string); } ... // (struct C and calls as yours) Is it correct that the DIP makes imports at aggregate scope shadow alias this lookups?
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 22:05:18 UTC, Timon Gehr wrote: On 10/10/2014 07:09 PM, IgorStepanov wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. - "C c; int i = c; //Error: c.a.i vs c.b.i static assert(is(C : int)); //Ok, because C is subtype of int anyway." So now we can have 'subtypes' whose instances cannot be stored in variables of the 'base type'? C++ allowed subtypes, which can not be casted to the base type (inheritance of two identical, non-virtual base classes). Ok, I've wrote my position, understood your and wait the decision of the arbitrator:) Such behaviour is inconsistent with both the reference implementation and the documentation (and the two happen to be mutually inconsistent on how 'is(:)' should behave as well. :o) ) - "The following pseudo-code illustrates this: [...] Finally, if resultSet contains only one candidate, the compiler will accept it." This process might very well never terminate but it could terminate in more cases if it did something better than the naive brute-force search. I.e. either report cycles or don't keep exploring around cycles, but just looping indefinitely on cycles like the following is IMO not a good course of action: struct S{ alias get this; T get(){ return T.init; } } struct T{ alias get this; S get(){ return S.init; } int x; alias x this; } void main(){ S s; int x=s; } This case described in DIP below. Recursion tree will be like: s.get s.get.get ->return, because T is already visited s.x -> win Furthermore, the following code compiles now, but doesn't under the approach described in the DIP. Is this an actual regression your pull introduces or is there a bug in the pseudocode?: class A{ alias x this; int x; } class B: A{ alias y this; int y; } void main(){ int x = new B(); } The same issue also needs to be considered if A and B are structs instead and B has an additional alias this to an A (the solution might also be part of a fix for the cycle issue). - "If resultSet contains more then one candidates, the compiler raises an error." struct A { short s; alias s this; } struct B { int i; alias i this; } struct C { A a; B b; alias a this; alias b this; } long l = C(); //What do you suggest?
Re: DIP66 - Multiple alias this
On 10/10/14 19:09, IgorStepanov via Digitalmars-d wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. This may be beyond the scope of the DIP, but is there any intention (or any need?) to set rules for how alias this should behave in the case of different protection levels for the base type and the alias? I ask because there is a known issue related to this: https://issues.dlang.org/show_bug.cgi?id=10996 ... but also because any rules set for this, might in principle affect the desirable priority rules for multiple alias this too.
Re: DIP66 - Multiple alias this
On 10/10/2014 3:06 PM, Timon Gehr wrote: On 10/10/2014 11:25 PM, Walter Bright wrote: Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected. Agreed. Do you suggest to overload alias this against imports and mixin templates? I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 22:18:36 UTC, Timon Gehr wrote: On 10/11/2014 12:07 AM, IgorStepanov wrote: On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright wrote: If 'a' and 'b' both contain overloads for function foo, then it should behave like imports do (which is a bit complex). Hmm. Now it works as I wrote it DIP pseudo-code: The pseudo-code doesn't actually specify that the arguments the identifier is being called with are considered at all. struct A { void foo(string); void foo(int); } struct B { void foo(double); } struct C { A a; B b; alias a this; alias b this; } C.foo("test"); //found only one acceptable foo: C.a.foo(string) C.foo(5); //1. Check a: found C.a.foo(int); //2. Check b: found C.b.foo(double); //3. Raise error: C.a.foo(int) vs C.b.foo(double) conflict C.foo(5.0);//found only one acceptable foo: C.b.foo(double) Is it Ok? ... That is the right behaviour. What happens in this case: struct A{ void foo(int); void foo(double); } struct B void foo(string); } ... // (struct C and calls as yours) C.foo("test"); //Ok, C.b.foo(string); C.foo(5); //Ok, C.a.foo(int); C.foo(5.0);//Ok, C.a.foo(double); Compiler simply tries to forward c.foo(ARG) -> c.a.foo(ARG) and c.b.foo(ARG). If only one is correct, compiler will accept it. If both is correct, compiler will raise an error.
Re: DIP66 - Multiple alias this
On 10/11/2014 12:29 AM, Walter Bright wrote: On 10/10/2014 3:06 PM, Timon Gehr wrote: On 10/10/2014 11:25 PM, Walter Bright wrote: Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected. Agreed. Do you suggest to overload alias this against imports and mixin templates? I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope. This allows for symbol hijacking (this is also the current behaviour): // --- module m; import std.stdio; // void foo(int x){ writeln("hi from m"); } // uncomment to hijack // --- module main; import std.stdio; struct T{ import m; alias s this; S s; } struct S{ void foo(int x){ writeln("hi from S"); } } void main(){ T t; t.foo(1); }
Re: DIP66 - Multiple alias this
On 10/10/2014 3:20 PM, IgorStepanov wrote: The same issue also needs to be considered if A and B are structs instead and B has an additional alias this to an A (the solution might also be part of a fix for the cycle issue). - "If resultSet contains more then one candidates, the compiler raises an error." struct A { short s; alias s this; } struct B { int i; alias i this; } struct C { A a; B b; alias a this; alias b this; } long l = C(); //What do you suggest? The rule would be if: long l = C.a(); long l = C.b(); both compile, then: long l = C(); must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports.
Re: DIP66 - Multiple alias this
On 10/10/2014 3:27 PM, Joseph Rushton Wakeling via Digitalmars-d wrote: On 10/10/14 19:09, IgorStepanov via Digitalmars-d wrote: I've created DIP for my pull request. DIP: http://wiki.dlang.org/DIP66 PR: https://github.com/D-Programming-Language/dmd/pull/3998 Please, comment it. This may be beyond the scope of the DIP, but is there any intention (or any need?) to set rules for how alias this should behave in the case of different protection levels for the base type and the alias? I like the C++ rule that says that access control is not considered for name lookup. I know it makes for some annoying results, but the simplicity of the rule makes it much more understandable. I ask because there is a known issue related to this: https://issues.dlang.org/show_bug.cgi?id=10996 ... but also because any rules set for this, might in principle affect the desirable priority rules for multiple alias this too.
Re: DIP66 - Multiple alias this
On 10/10/2014 3:46 PM, Timon Gehr wrote: On 10/11/2014 12:29 AM, Walter Bright wrote: On 10/10/2014 3:06 PM, Timon Gehr wrote: On 10/10/2014 11:25 PM, Walter Bright wrote: Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected. Agreed. Do you suggest to overload alias this against imports and mixin templates? I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope. This allows for symbol hijacking (this is also the current behaviour): // --- module m; import std.stdio; // void foo(int x){ writeln("hi from m"); } // uncomment to hijack // --- module main; import std.stdio; struct T{ import m; alias s this; S s; } struct S{ void foo(int x){ writeln("hi from S"); } } void main(){ T t; t.foo(1); } Hmm. Good point. The alias this should be done before imports.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote: On 10/10/2014 3:20 PM, IgorStepanov wrote: The same issue also needs to be considered if A and B are structs instead and B has an additional alias this to an A (the solution might also be part of a fix for the cycle issue). - "If resultSet contains more then one candidates, the compiler raises an error." struct A { short s; alias s this; } struct B { int i; alias i this; } struct C { A a; B b; alias a this; alias b this; } long l = C(); //What do you suggest? The rule would be if: long l = C.a(); long l = C.b(); both compile, then: long l = C(); must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports. So it is.
Re: DIP66 - Multiple alias this
BTW. Overloaded functions in PR resolves un-properly (raises error even if can be resolved correct function) However it's easy to fix and I'll do it tomorrow.
Re: DIP66 - Multiple alias this
On Friday, 10 October 2014 at 22:51:34 UTC, Walter Bright wrote: On 10/10/2014 3:46 PM, Timon Gehr wrote: On 10/11/2014 12:29 AM, Walter Bright wrote: On 10/10/2014 3:06 PM, Timon Gehr wrote: On 10/10/2014 11:25 PM, Walter Bright wrote: Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected. Agreed. Do you suggest to overload alias this against imports and mixin templates? I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope. This allows for symbol hijacking (this is also the current behaviour): // --- module m; import std.stdio; // void foo(int x){ writeln("hi from m"); } // uncomment to hijack // --- module main; import std.stdio; struct T{ import m; alias s this; S s; } struct S{ void foo(int x){ writeln("hi from S"); } } void main(){ T t; t.foo(1); } Hmm. Good point. The alias this should be done before imports. Symmetrically. You may use symbol from import, uncomment it in aliased type and hijack it.
Re: DIP66 - Multiple alias this
On 10/10/2014 4:23 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote: must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports. So it is. Good! The same rule applies for overloading.
Re: DIP66 - Multiple alias this
On 2014-10-11 00:52, Walter Bright wrote: I like the C++ rule that says that access control is not considered for name lookup. I know it makes for some annoying results, but the simplicity of the rule makes it much more understandable. I'm not so sure about that. Perhaps it makes it more understandable for a language designer. But not for a user. You try to call a function but you get a conflict with a private symbol. The user will get frustrated thinking: "stupid compiler, of course I want to call the public function". -- /Jacob Carlborg
Re: DIP66 - Multiple alias this
On Saturday, 11 October 2014 at 00:00:48 UTC, Walter Bright wrote: On 10/10/2014 4:23 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote: must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports. So it is. Good! The same rule applies for overloading. I've implemented overloading: https://github.com/D-Programming-Language/dmd/pull/3998/files#diff-17b22eae29e74ce6ec29037438b5031cR2136 Please, tell me, what changes should I make to the DIP as a result of yesterday's discussions. And please, tell your opinion about "is" issue: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } void foo(T)(T arg) if(is(T : int)) { ... } foo(C()); //Should it pass or not?
Re: DIP66 - Multiple alias this
On 10/11/2014 3:42 AM, Jacob Carlborg wrote: On 2014-10-11 00:52, Walter Bright wrote: I like the C++ rule that says that access control is not considered for name lookup. I know it makes for some annoying results, but the simplicity of the rule makes it much more understandable. I'm not so sure about that. Perhaps it makes it more understandable for a language designer. But not for a user. You try to call a function but you get a conflict with a private symbol. The user will get frustrated thinking: "stupid compiler, of course I want to call the public function". The theory is that simpler rules are better than complex rules, even if the simpler rules aren't always ideal.
Re: DIP66 - Multiple alias this
On 10/11/2014 7:23 AM, IgorStepanov wrote: On Saturday, 11 October 2014 at 00:00:48 UTC, Walter Bright wrote: On 10/10/2014 4:23 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote: must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports. So it is. Good! The same rule applies for overloading. I've implemented overloading: https://github.com/D-Programming-Language/dmd/pull/3998/files#diff-17b22eae29e74ce6ec29037438b5031cR2136 Please, tell me, what changes should I make to the DIP as a result of yesterday's discussions. At the very least, it should say it resolves ambiguities the same way that imports and template mixins do. And please, tell your opinion about "is" issue: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } void foo(T)(T arg) if(is(T : int)) { ... } foo(C()); //Should it pass or not? There's a rule with imports that if the same symbol is reachable via multiple paths through the imports, that it is not an ambiguity error. Here, the same type is reachable through multiple alias this paths, so by analogy it shouldn't be an error.
Re: DIP66 - Multiple alias this
On Sunday, 12 October 2014 at 04:31:22 UTC, Walter Bright wrote: On 10/11/2014 7:23 AM, IgorStepanov wrote: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } void foo(T)(T arg) if(is(T : int)) { ... } foo(C()); //Should it pass or not? There's a rule with imports that if the same symbol is reachable via multiple paths through the imports, that it is not an ambiguity error. Here, the same type is reachable through multiple alias this paths, so by analogy it shouldn't be an error. It's the same type, but different symbols; actual accesses would be ambiguous. `is(T : int)` shouldn't evaluate to true if `int a = T.init;` would fail.
Re: DIP66 - Multiple alias this
On 11/10/14 00:52, Walter Bright via Digitalmars-d wrote: I like the C++ rule that says that access control is not considered for name lookup. I know it makes for some annoying results, but the simplicity of the rule makes it much more understandable. That's fine. I just wanted to be sure that there wasn't a risk of multiple alias this breaking in unpleasant ways, if/when https://issues.dlang.org/show_bug.cgi?id=10996 is fixed.
Re: DIP66 - Multiple alias this
On Sunday, 12 October 2014 at 08:36:05 UTC, Marc Schütz wrote: On Sunday, 12 October 2014 at 04:31:22 UTC, Walter Bright wrote: On 10/11/2014 7:23 AM, IgorStepanov wrote: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } void foo(T)(T arg) if(is(T : int)) { ... } foo(C()); //Should it pass or not? There's a rule with imports that if the same symbol is reachable via multiple paths through the imports, that it is not an ambiguity error. Here, the same type is reachable through multiple alias this paths, so by analogy it shouldn't be an error. It's the same type, but different symbols; actual accesses would be ambiguous. `is(T : int)` shouldn't evaluate to true if `int a = T.init;` would fail. I found an example of a situation that is bothering me. Let we have a persistence framework, which provides a storing D object in some persistence storage: DB, file et c. In introduces paired functions store/load and special type PersistenceObject. If stored type is subtype of PersistenceObject it converts to PersistenceObject and PersistenceObject.load(stream) called for loading object (and PersistenceObject.store(stream) for storing). Otherwice if object can't be converted to PersistenceObject it should be serialized via "serialize" function (or deserialized via "deserialize"). struct PersistenceFramework { void store(T)(T arg) if (is(T : PersistenceObject)) { PersistenceObject po = arg; arg.store(stream); } void store(T)(T arg) if (!is(T : PersistenceObject)) { PersistenceObject po = arg; store(serialize(arg)); } void load(T)(ref T arg) if (is(T : PersistenceObject)) { PersistenceObject po = arg; arg.load(stream); } void load(T)(ref T arg) if (!is(T : PersistenceObject)) { PersistenceObject po = arg; load(serialize(arg)); } Stream stream; } / And we have the next types which we want to store and load */ struct Role { ... } struct User { Role role; PersistenceObject po; //... alias role this; alias po this; } /*/ User u; persistenceFramework.load(u) //... persistenceFramework.store(u); /**/ Role is not subtype of PersistenceObject thus all works ok. We can store User via User.po and load it again; Some time later, Role designer decided that Role should be subtype of PersistenceObject and changed Role definition: struct Role { ... PersistenceObject po; alias po this; } Now, User can not be converted to PersistenceObject because there are two path to convert: User.po and User.role.po; Storing code after this change will be copiled successfully (if we follow your "is" rule), however object will be tried to load via "void load(T)(ref T arg) if (!is(T : PersistenceObject))". Because object was saved via "void store(T)(T arg) if (is(T : PersistenceObject))" at the previous program run, user will not be loaded succesfully. Moreover, you will get an strange unexpected program behaviour and will be hard to find real error cause. /*/ And finally, if you want to check, if you Type _really_ can be converted to AnotherType, you can use the next check: void foo(Type)(Type arg) if (is(typeof({AnotherType x = Type.init;}))) { }
Re: DIP66 - Multiple alias this
On 10/12/2014 06:28 AM, Walter Bright wrote: On 10/11/2014 3:42 AM, Jacob Carlborg wrote: On 2014-10-11 00:52, Walter Bright wrote: I like the C++ rule that says that access control is not considered for name lookup. I know it makes for some annoying results, but the simplicity of the rule makes it much more understandable. I'm not so sure about that. Perhaps it makes it more understandable for a language designer. But not for a user. You try to call a function but you get a conflict with a private symbol. The user will get frustrated thinking: "stupid compiler, of course I want to call the public function". The theory is that simpler rules are better than complex rules, even if the simpler rules aren't always ideal. Public symbols conflicting with private symbols are not just not ideal, they are a major PITA. The procedure for resolving ambiguities using alias introduces new private symbols itself!
Re: DIP66 - Multiple alias this
On 10/10/14 6:10 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 21:26:49 UTC, Steven Schveighoffer wrote: An example: foo(T)(T t) if(is(T : int)) { someFuncThatTakesInt(t); } foo(T)(T t) if(!is(T : int) && is(T.shadow : int)) { someFuncThatTakesInt(t.shadow); } struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B shadow; alias a this; alias shadow this; } C c; foo(c); // should compile, but I think your DIP makes it fail due to ambiguity You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect. -Steve
Re: DIP66 - Multiple alias this
On Sunday, 12 October 2014 at 23:02:13 UTC, Steven Schveighoffer wrote: On 10/10/14 6:10 PM, IgorStepanov wrote: On Friday, 10 October 2014 at 21:26:49 UTC, Steven Schveighoffer wrote: An example: foo(T)(T t) if(is(T : int)) { someFuncThatTakesInt(t); } foo(T)(T t) if(!is(T : int) && is(T.shadow : int)) { someFuncThatTakesInt(t.shadow); } struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B shadow; alias a this; alias shadow this; } C c; foo(c); // should compile, but I think your DIP makes it fail due to ambiguity You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect. -Steve Hmm. I've written case (my previous post), when returning false from is(T: S), where T has many pathes to S is dangerous. However your words also contain the truth. I don't know what we need to do. Maybe we should raise error during "is" semantic? Please, read my example and say your opinion.
Re: DIP66 - Multiple alias this
Advantage of ky way is a more strictness then your way: if function with if(is(T: S)) will be called, error will be raised at the first trying of convert T to S. And we don't give the opportunity of possible error to spread away from the place of origin.
Re: DIP66 - Multiple alias this
On 10/12/14 7:16 PM, IgorStepanov wrote: On Sunday, 12 October 2014 at 23:02:13 UTC, Steven Schveighoffer wrote: On 10/10/14 6:10 PM, IgorStepanov wrote: You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect. Hmm. I've written case (my previous post), when returning false from is(T: S), where T has many pathes to S is dangerous. OK, I didn't understand your case before, but I just got it. I understand what you mean, but this isn't anything new -- one can cause weird problems by creating diamond-pattern interfaces also. I do not actually think it is dangerous, because one would not leave an error call in their code. So for a future change to a library to "mystically" make a function start working is not a danger, because said code wasn't sitting there broken in the first place. I will note, that for diamond problem interfaces, the compiler seems to take a different track than your DIP: interface A {} interface B : A {} interface C : A {} class X : B, C {} static assert(is(X : A)); void main() { A a = new C; // works, not sure if it's B.A or C.A } I know this is a different problem -- we aren't pointing at two different concrete implementations. -Steve
Re: DIP66 - Multiple alias this
On Monday, 13 October 2014 at 00:54:13 UTC, Steven Schveighoffer wrote: On 10/12/14 7:16 PM, IgorStepanov wrote: On Sunday, 12 October 2014 at 23:02:13 UTC, Steven Schveighoffer wrote: On 10/10/14 6:10 PM, IgorStepanov wrote: You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect. Hmm. I've written case (my previous post), when returning false from is(T: S), where T has many pathes to S is dangerous. OK, I didn't understand your case before, but I just got it. I understand what you mean, but this isn't anything new -- one can cause weird problems by creating diamond-pattern interfaces also. I do not actually think it is dangerous, because one would not leave an error call in their code. So for a future change to a library to "mystically" make a function start working is not a danger, because said code wasn't sitting there broken in the first place. I will note, that for diamond problem interfaces, the compiler seems to take a different track than your DIP: interface A {} interface B : A {} interface C : A {} class X : B, C {} static assert(is(X : A)); void main() { A a = new C; // works, not sure if it's B.A or C.A } I know this is a different problem -- we aren't pointing at two different concrete implementations. -Steve This is fundamentally different situation: interfaces haven't a state, thus don't care what interface will be getted: B.C or C.C. Moreover, we can think that we have only one base C (like virtual inherited class in C++). Alias this case requires a completely different approach.
Re: DIP66 - Multiple alias this
On 10/11/2014 7:23 AM, IgorStepanov wrote: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } My preferred solution would be to reject the 2nd alias declaration outright. I don't see any value in intentionally creating the above pattern, _if_ it occurs then it's most likely due to an unintentional side-effect of a re-factoring, thus it should error out as close as possible to the real error.
Re: DIP66 - Multiple alias this
On Monday, 13 October 2014 at 15:21:32 UTC, Daniel N wrote: On 10/11/2014 7:23 AM, IgorStepanov wrote: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } My preferred solution would be to reject the 2nd alias declaration outright. I don't see any value in intentionally creating the above pattern, _if_ it occurs then it's most likely due to an unintentional side-effect of a re-factoring, thus it should error out as close as possible to the real error. This code tell that C is subtype of A and C is subtype of B. User can use this fact in his code: void foo(B); C c = new C; foo(c); //Ok. Of course, we shouldn't allow user to cast c to int: int i = c; //wrong However, user can explicitly cast c to his subtype, which is convertable to int: int i = cast(B)c; //Ok Summarizing, I disagree with suggestion disallow this code at type semantic stage.
Re: DIP66 - Multiple alias this
On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov wrote: This code tell that C is subtype of A and C is subtype of B. User can use this fact in his code: void foo(B); C c = new C; foo(c); //Ok. Of course, we shouldn't allow user to cast c to int: int i = c; //wrong However, user can explicitly cast c to his subtype, which is convertable to int: int i = cast(B)c; //Ok Summarizing, I disagree with suggestion disallow this code at type semantic stage. I agree. It will also make possible to break already working disambugation of `foo(c)` kind but adding new `alias this` to one of subtypes independently. That sounds annoying.
Re: DIP66 - Multiple alias this
On Wednesday, 15 October 2014 at 02:46:05 UTC, Dicebot wrote: On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov wrote: This code tell that C is subtype of A and C is subtype of B. User can use this fact in his code: void foo(B); C c = new C; foo(c); //Ok. Of course, we shouldn't allow user to cast c to int: int i = c; //wrong However, user can explicitly cast c to his subtype, which is convertable to int: int i = cast(B)c; //Ok Summarizing, I disagree with suggestion disallow this code at type semantic stage. I agree. It will also make possible to break already working disambugation of `foo(c)` kind but adding new `alias this` to one of subtypes independently. That sounds annoying. I guess the best part of D is, you have the means to fix anything you disagree with yourself... I can add a static assert to my class and be happy. I have another idea, we could define that the shortest conversion chain wins, analogous to type promotions, that makes it possible to contain the issue inside C. class C { A a; B b; int disambiguate_int() { return a; } alias a this; alias b this; alias disambiguate_int this; static assert(__traits(compiles, {int _ = C.init;}), "Ambiguous alias this"); } i.e. this assert should pass.
Re: DIP66 - Multiple alias this
On Wednesday, 15 October 2014 at 03:49:41 UTC, Daniel N wrote: On Wednesday, 15 October 2014 at 02:46:05 UTC, Dicebot wrote: On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov wrote: This code tell that C is subtype of A and C is subtype of B. User can use this fact in his code: void foo(B); C c = new C; foo(c); //Ok. Of course, we shouldn't allow user to cast c to int: int i = c; //wrong However, user can explicitly cast c to his subtype, which is convertable to int: int i = cast(B)c; //Ok Summarizing, I disagree with suggestion disallow this code at type semantic stage. I agree. It will also make possible to break already working disambugation of `foo(c)` kind but adding new `alias this` to one of subtypes independently. That sounds annoying. I guess the best part of D is, you have the means to fix anything you disagree with yourself... I can add a static assert to my class and be happy. I have another idea, we could define that the shortest conversion chain wins, analogous to type promotions, that makes it possible to contain the issue inside C. class C { A a; B b; int disambiguate_int() { return a; } alias a this; alias b this; alias disambiguate_int this; static assert(__traits(compiles, {int _ = C.init;}), "Ambiguous alias this"); } i.e. this assert should pass. In first edition I've implemented rule, when if type defines alias this directly, this alias hides all indirect aliases with the same type. However Andrey said that we should implement the strictest rules as possible and maybe relax them later. Thus I implemented current rules, but saved the old implemetation of search. After some time we will able to return to first rule. It's not hard.
Re: DIP66 - Multiple alias this
Bump.
Re: DIP66 - Multiple alias this
On Wednesday, 15 October 2014 at 09:50:17 UTC, IgorStepanov wrote: In first edition I've implemented rule, when if type defines alias this directly, this alias hides all indirect aliases with the same type. However Andrey said that we should implement the strictest rules as possible and maybe relax them later. Thus I implemented current rules, but saved the old implemetation of search. After some time we will able to return to first rule. It's not hard. I see, in order to prevent any accidental shadowing, maybe one can consider "override alias this", if we decide to make a relaxed version in the future?
Re: DIP66 - Multiple alias this
On Monday, 20 October 2014 at 00:23:46 UTC, Daniel N wrote: On Wednesday, 15 October 2014 at 09:50:17 UTC, IgorStepanov wrote: In first edition I've implemented rule, when if type defines alias this directly, this alias hides all indirect aliases with the same type. However Andrey said that we should implement the strictest rules as possible and maybe relax them later. Thus I implemented current rules, but saved the old implemetation of search. After some time we will able to return to first rule. It's not hard. I see, in order to prevent any accidental shadowing, maybe one can consider "override alias this", if we decide to make a relaxed version in the future? Make sense. I think we should postpone but not forgotten this feature. When main part will be merged, we will able to start discussion about override alias this. What about the other features?