www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proof of concept - library AA

reply Martin Nowak <code+news.digitalmars dawg.eu> writes:
Would be interesting to get some opinions on this.

https://github.com/D-Programming-Language/druntime/pull/1282
May 24 2015
next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:
 Would be interesting to get some opinions on this.

 https://github.com/D-Programming-Language/druntime/pull/1282
Looks like a good step in the right direction. Some questions about:
 This provides a strong incentive to no longer use the magic 
 semantics of the builtin AAs,
Could you elaborate on what these magic semantics are?
 and no easy solution exists for the ++aa[key1][key2] case.
Is this specific to the pre-increment? aa[key1][key2]++ is generally a useful pattern.
May 24 2015
next sibling parent "IgorStepanov" <wazar mail.ru> writes:
On Sunday, 24 May 2015 at 15:13:41 UTC, Vladimir Panteleev wrote:
 On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:
 Would be interesting to get some opinions on this.

 https://github.com/D-Programming-Language/druntime/pull/1282
Looks like a good step in the right direction. Some questions about:
 This provides a strong incentive to no longer use the magic 
 semantics of the builtin AAs,
Could you elaborate on what these magic semantics are?
 and no easy solution exists for the ++aa[key1][key2] case.
Is this specific to the pre-increment? aa[key1][key2]++ is generally a useful pattern.
The general idea that library aa has a vtbl, and standart AA fuctions like _aaGetX will access to our AA via vtbl. Compiler will operate with aa via all those _aaGetX, _aaLen et c. Thus aa[x][y]++; will work as early.
May 25 2015
prev sibling parent reply "Martin Nowak" <code dawg.eu> writes:
On Sunday, 24 May 2015 at 15:13:41 UTC, Vladimir Panteleev wrote:
 Could you elaborate on what these magic semantics are?

 and no easy solution exists for the ++aa[key1][key2] case.
Is this specific to the pre-increment? aa[key1][key2]++ is generally a useful pattern.
This applies to pre/post increment as well as assignment and opOpAssign. When an lvalue is needed the compiler will call a special runtime function GetX to obtain an lvalue for aa[key1], i.e. the entry will be default initialized iff missing. If the expression is an rvalue though (aa[key1][key2]), a missing key1 will trigger a range error. In an opIndex(Key) you have no idea whether the whole expression I an lvalue or an rvalue. IIRC the construction/assignment of a value is also handled specifically.
May 27 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Wednesday, 27 May 2015 at 14:12:02 UTC, Martin Nowak wrote:
 On Sunday, 24 May 2015 at 15:13:41 UTC, Vladimir Panteleev 
 wrote:
 Could you elaborate on what these magic semantics are?

 and no easy solution exists for the ++aa[key1][key2] case.
Is this specific to the pre-increment? aa[key1][key2]++ is generally a useful pattern.
This applies to pre/post increment as well as assignment and opOpAssign. When an lvalue is needed the compiler will call a special runtime function GetX to obtain an lvalue for aa[key1], i.e. the entry will be default initialized iff missing. If the expression is an rvalue though (aa[key1][key2]), a missing key1 will trigger a range error. In an opIndex(Key) you have no idea whether the whole expression I an lvalue or an rvalue. IIRC the construction/assignment of a value is also handled specifically.
BTW, may be we should create DIP about opIndex extending? What do you want about following? Let, if opIndex is template, and the first template argument is a bool value, compiler should pass true, if this is a part of l-value expression: struct Foo { Foo[] children; this(int value) { this.value = value; } int value; ref Foo opIndex(bool lvl)(size_t idx) { if (idx < children.length) return children[idx]; static if (lvl) { children.length = idx + 1; return children[idx]; } else { throw new Exception("out of bounds"); } } } Foo f; f[5][3] = Foo(42); translates to f.opIndex!(true)(5).opIndex!(true)(3) = Foo(42); auto x = f[5][4]; translates to auto x = f.opIndex!(false)(5).opIndex!(false)(3);
May 27 2015
next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Wed, May 27, 2015 at 05:16:51PM +0000, IgorStepanov via Digitalmars-d wrote:
 On Wednesday, 27 May 2015 at 14:12:02 UTC, Martin Nowak wrote:
On Sunday, 24 May 2015 at 15:13:41 UTC, Vladimir Panteleev wrote:
Could you elaborate on what these magic semantics are?

and no easy solution exists for the ++aa[key1][key2] case.
Is this specific to the pre-increment? aa[key1][key2]++ is generally a useful pattern.
This applies to pre/post increment as well as assignment and opOpAssign. When an lvalue is needed the compiler will call a special runtime function GetX to obtain an lvalue for aa[key1], i.e. the entry will be default initialized iff missing. If the expression is an rvalue though (aa[key1][key2]), a missing key1 will trigger a range error. In an opIndex(Key) you have no idea whether the whole expression I an lvalue or an rvalue. IIRC the construction/assignment of a value is also handled specifically.
BTW, may be we should create DIP about opIndex extending?
[...] See: https://issues.dlang.org/show_bug.cgi?id=7753 This issue has been known since 2012. T -- Genius may have its limitations, but stupidity is not thus handicapped. -- Elbert Hubbard
May 27 2015
prev sibling parent reply "Martin Nowak" <code dawg.eu> writes:
On Wednesday, 27 May 2015 at 17:16:53 UTC, IgorStepanov wrote:
 Foo f;
 f[5][3] = Foo(42); translates to
     f.opIndex!(true)(5).opIndex!(true)(3) = Foo(42);

 auto x = f[5][4]; translates to
     auto x = f.opIndex!(false)(5).opIndex!(false)(3);
We shouldn't replace opIndexAssign though, b/c default construction + assignment is more expensive than constructing in-place.
May 29 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 29 May 2015 at 11:17:00 UTC, Martin Nowak wrote:
 On Wednesday, 27 May 2015 at 17:16:53 UTC, IgorStepanov wrote:
 Foo f;
 f[5][3] = Foo(42); translates to
    f.opIndex!(true)(5).opIndex!(true)(3) = Foo(42);

 auto x = f[5][4]; translates to
    auto x = f.opIndex!(false)(5).opIndex!(false)(3);
We shouldn't replace opIndexAssign though, b/c default construction + assignment is more expensive than constructing in-place.
Sorry, I meant f.opIndex!(true)(5).opIndexAssign(Foo(42), 3);
May 29 2015
parent reply "Martin Nowak" <code dawg.eu> writes:
On Friday, 29 May 2015 at 11:22:53 UTC, IgorStepanov wrote:
 Sorry, I meant
 f.opIndex!(true)(5).opIndexAssign(Foo(42), 3);
Added to the ER. https://issues.dlang.org/show_bug.cgi?id=7753#c6
May 29 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 29 May 2015 at 12:52:29 UTC, Martin Nowak wrote:
 On Friday, 29 May 2015 at 11:22:53 UTC, IgorStepanov wrote:
 Sorry, I meant
 f.opIndex!(true)(5).opIndexAssign(Foo(42), 3);
Added to the ER. https://issues.dlang.org/show_bug.cgi?id=7753#c6
Thanks, but unfortunately, writing enhacement request to bugzilla is equals to writing to /dev/null :) I'll create a DIP about this, when I'll have a free time. What do you want about this syntax? Maybe you may suggest a better solution?
May 29 2015
next sibling parent "Martin Nowak" <code dawg.eu> writes:
On Friday, 29 May 2015 at 13:12:58 UTC, IgorStepanov wrote:
 Thanks, but unfortunately, writing enhacement request to 
 bugzilla is equals to writing to /dev/null :)
No it's not, it keeps us from rediscussing the same stuff over and over.
 I'll create a DIP about this, when I'll have a free time.
As the amount of DIPs grows, DIPs become the new ER. The problem is that this enhancement is of low priority and there is nothing you can do to change that, except for making a convincing case and a backward compatible implementation.
 What do you want about this syntax? Maybe you may suggest a 
 better solution?
A separate opIndexCreate might be better, b/c it allows you to have a ref return for one and an rvalue return for the other function. It also allows to use those operands as polymorphic functions in classes.
May 29 2015
prev sibling parent reply "Martin Nowak" <code dawg.eu> writes:
On Friday, 29 May 2015 at 13:12:58 UTC, IgorStepanov wrote:
 What do you want about this syntax? Maybe you may suggest a 
 better solution?
The discussion drifts a little OT, if we have opIndexCreate, then the library AA can be more compatible, but it still won't be a drop-in replacement.
May 29 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 29 May 2015 at 17:52:58 UTC, Martin Nowak wrote:
 On Friday, 29 May 2015 at 13:12:58 UTC, IgorStepanov wrote:
 What do you want about this syntax? Maybe you may suggest a 
 better solution?
The discussion drifts a little OT, if we have opIndexCreate, then the library AA can be more compatible, but it still won't be a drop-in replacement.
We went a long way in this direction and if we don't come to the result yet, that, I think, we haven't thought-out plan. I suggest you to answer to the following two question: 1. What way to transit to the new AA would be acceptable? You rejects my way (and I could not continue to work in the winter), and AFAIR you principial objection was: "aaLiteral is non- safe for the unsafe code and it is breakage". However, aaLiteral attributes hasn't checked by compiler, because it was used in e2ir. _d_assocarrayliteralTX is not safe or pure, but aa can be used in safe pure code. We may insert additional checks, see aaLiteral attributes, and raise deprecation message, if attributes are inacceptable. If it is the last objection, we may repeat compiler-side part for the new AA template. Othrewice, lets invent another way. 2. What issues disallows us to implement full library AA? Except .stringof, .mangleof, and other compiler magic. I see only two issues: opIndexCreate and building aa from literals.
May 29 2015
parent reply "Martin Nowak" <code dawg.eu> writes:
On Friday, 29 May 2015 at 21:58:16 UTC, IgorStepanov wrote:
 I suggest you to answer to the following two question:
 1. What way to transit to the new AA would be acceptable?
One that doesn't break any code, carefully deprecates necessary semantic changes, and provides an improved implementation.
 You rejects my way (and I could not continue to work in the 
 winter), and AFAIR you principial objection was: "aaLiteral is 
 non- safe for the unsafe code and it is breakage".
The objection was too much code breakage for an inferior implementation. https://github.com/D-Programming-Language/druntime/pull/934#issuecomment-66888409
 We may insert additional checks, see aaLiteral attributes, and 
 raise deprecation message, if attributes are inacceptable.
Maybe we can hack around the attribute incompatibilities in the compiler, we'll have to add deprecations at some point anyhow.
 2. What issues disallows us to implement full library AA? 
 Except .stringof, .mangleof, and other compiler magic.
 I see only two issues: opIndexCreate and building aa from 
 literals.
- error messages - attributes - literals (especially polysemous initializers, i.e. ubyte[ubyte] aa = [0:1, 1:2]) - implicit tail const conversion Val[Key] -> const(Val)[Key] - lots of magic around making Key const - delete aa[key] - lots of other small details (grep for Taarray in src/expression.c) This is a heavily used built-in type, we can't risk a rewrite that breaks lots of code.
May 29 2015
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/29/15 4:41 PM, Martin Nowak wrote:
 On Friday, 29 May 2015 at 21:58:16 UTC, IgorStepanov wrote:
 I suggest you to answer to the following two question:
 1. What way to transit to the new AA would be acceptable?
One that doesn't break any code, carefully deprecates necessary semantic changes, and provides an improved implementation.
I suggest first we build a library AA that sits beside real AA, even if it doesn't . Then we create a test suite to prove that the library AA can be a drop in replacement. Then replace it :) Put it in code.dlang or std.experimental. It's better to have code to play with and test than it is to do everything at once. -Steve
May 29 2015
parent reply "Martin Nowak" <code dawg.eu> writes:
On Saturday, 30 May 2015 at 00:50:39 UTC, Steven Schveighoffer 
wrote:
 I suggest first we build a library AA that sits beside real AA, 
 even if it doesn't . Then we create a test suite to prove that 
 the library AA can be a drop in replacement. Then replace it :)
Writing the AA is NOT the problem, but I doubt we can get compatible enough to replace the built-in AA. Rather it'll require to deprecate a few built-in AA semantics and adding operator and literal extensions for the library type. Hence the proposal to start with a HQ library AA and incrementally converge them.
May 30 2015
parent reply "Uranuz" <neuranuz gmail.com> writes:
On Saturday, 30 May 2015 at 08:22:21 UTC, Martin Nowak wrote:
 On Saturday, 30 May 2015 at 00:50:39 UTC, Steven Schveighoffer 
 wrote:
 I suggest first we build a library AA that sits beside real 
 AA, even if it doesn't . Then we create a test suite to prove 
 that the library AA can be a drop in replacement. Then replace 
 it :)
Writing the AA is NOT the problem, but I doubt we can get compatible enough to replace the built-in AA. Rather it'll require to deprecate a few built-in AA semantics and adding operator and literal extensions for the library type. Hence the proposal to start with a HQ library AA and incrementally converge them.
My idea is slihtly of topic. I thiking about some API for array and associative array literals. Something similar to our range API: front, popFront, etc. It would be good (as I think) if programmer could be able to use Array, or AA literal directly (like maybe initializer list in C++). So for example some class or struct could be initialized from AA literal directly. And another option could be having heterogenous types in Array and AA, so we could use them in a way we work with tuples. So we could use AA literal to initialize JSON objects directly for example using different types of values inside. auto json = [ "name": "John", "age": 30, "interests": ["programming", "D lang"] ]; Also we could be able to initialize tuple from such heterogenous Array literal. So literals would be not only available for processing by core language and runtime, but also for regular D classes, structs and templates. It could significantly help with initializing complex objects. It would be big change. But what do you thing about just about idea?
Jul 07 2015
parent reply "Martin Nowak" <code dawg.eu> writes:
On Wednesday, 8 July 2015 at 06:11:25 UTC, Uranuz wrote:
 My idea is slihtly of topic.
 I thiking about some API for array and associative array 
 literals.
There is already an API for array literals, typesafe variadic arguments. void foo(int[] literal...); foo([0, 1, 2, 3]);
 But what do you thing about just about idea?
We discussed this already. https://issues.dlang.org/show_bug.cgi?id=11658 AA and array literals come with literals coercion rules, heterogeneous literals would make the semantics of the literal depend on the callsite. We already have TypeTuple/Arguments for heterogeneous tuples.
Jul 08 2015
parent reply "Uranuz" <neuranuz gmail.com> writes:
On Wednesday, 8 July 2015 at 08:24:00 UTC, Martin Nowak wrote:
 On Wednesday, 8 July 2015 at 06:11:25 UTC, Uranuz wrote:
 My idea is slihtly of topic.
 I thiking about some API for array and associative array 
 literals.
There is already an API for array literals, typesafe variadic arguments. void foo(int[] literal...); foo([0, 1, 2, 3]);
 But what do you thing about just about idea?
We discussed this already. https://issues.dlang.org/show_bug.cgi?id=11658 AA and array literals come with literals coercion rules, heterogeneous literals would make the semantics of the literal depend on the callsite. We already have TypeTuple/Arguments for heterogeneous tuples.
As far as I understand from that discussion it this feature was not accepted because of template bloat. Am I wrong? But it could be very useful in situations. Another way is to create specific parser that will parse some JSON-like DSL and genetate some code after it that will create specific data structure. But I think it not so nice an will lead to creation of different flavours and parsers for such DSL's.
Jul 08 2015
parent Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 07/08/2015 02:20 PM, Uranuz wrote:
 As far as I understand from that discussion it this feature was not
 accepted because of template bloat. Am I wrong?
The main reason is that AA literals already have an incompatible semantic. pragma(msg, typeof(["0": ubyte(0), "1": ushort(1)])); prints int[string] Heterogeneous AA literals would require to move that type coercion from the compiler into the AA constructor. That's bad b/c the behavior of the literal would depend on the callee. And it would be difficult to avoid type conversion at runtime and template bloat for each different literal.
Jul 08 2015
prev sibling next sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 29 May 2015 at 22:41:13 UTC, Martin Nowak wrote:
 On Friday, 29 May 2015 at 21:58:16 UTC, IgorStepanov wrote:
 I suggest you to answer to the following two question:
 1. What way to transit to the new AA would be acceptable?
One that doesn't break any code, carefully deprecates necessary semantic changes, and provides an improved implementation.
 You rejects my way (and I could not continue to work in the 
 winter), and AFAIR you principial objection was: "aaLiteral is 
 non- safe for the unsafe code and it is breakage".
The objection was too much code breakage for an inferior implementation. https://github.com/D-Programming-Language/druntime/pull/934#issuecomment-66888409
 We may insert additional checks, see aaLiteral attributes, and 
 raise deprecation message, if attributes are inacceptable.
I recall a list of your demands. ------------------------------------------------------------ 1. open addressing 2. efficient construction, insertion and assignment (no extra copies or postblits) 3. fully CTFEable (includes storing literals in the data segment) 4. type and attribute correctness 5. get's rid of TypeInfo methods (toHash, opEquals, tsize) 6. GC NO_SCAN for values ------------------------------------------------------------ 1. It depends only on library AA implementation, not on dmd-druntime interaction. 2. This goal was achieved in my last AA version. Open addressing edition may get us troubles with it, but I think this troubles are solvable. 3. Storing CTFE literals was implemented in that implementation. Maybe not quite right, but the problem is also solvable. 4. This solution follows directly from template implementation. 5. Was done. 6. This problem is also solvable. Now about backward compatibility: AFAIR you pointed to the one breakage: the forced checking of attribute correctness. I then entered into an argument with you, but I forgot, that the forced attribute checking was disabled in the last edition: Yes, aaLiteral gets attributes from the underlying code, and if AA constructor was unsafe, aaLiteral was unsafe too. However, AssocArrayLiteralExp::toElem doesn't check the attribute correctness and constructing of unsafe or non-throwable AA from safe or throwable code was allowed. Or I forgot about some other breakage cases?
 2. What issues disallows us to implement full library AA? 
 Except .stringof, .mangleof, and other compiler magic.
 I see only two issues: opIndexCreate and building aa from 
 literals.
- error messages - attributes - literals (especially polysemous initializers, i.e. ubyte[ubyte] aa = [0:1, 1:2]) - implicit tail const conversion Val[Key] -> const(Val)[Key] - lots of magic around making Key const - delete aa[key] - lots of other small details (grep for Taarray in src/expression.c) This is a heavily used built-in type, we can't risk a rewrite that breaks lots of code.
- error messages
Is it a significant problem? If compiler allows correct code, disallows incorrect code and gets a clear error messages there there is no problem, I think. Of cource, we will need to write pretty error messages, implement correct .stringof in dmd (to writting type name as V[K], not as AA!(K, V).
 - attributes
We will able to deprecate attribute violations in transitional version (with vtbl).
 - literals (especially polysemous initializers, i.e. 
 ubyte[ubyte] aa = [0:1, 1:2])
Yes, this is the first main trouble.
 - implicit tail const conversion Val[Key] -> const(Val)[Key]
May be we may add "alias this"-es for all all those variants? Something like ... struct AA(K, V) { alias getCKeyMval this; alias getMKeyCval this; alias getCKeyCval this; property { ref AA!(const(K), V) getCKeyMval() { return *cast(typeof(return)*)&this; } ref AA!(K, const(V)) getMKeyCval() { return *cast(typeof(return)*)&this; } ref AA!(const(K), const(V)) getCKeyCval() { return *cast(typeof(return)*)&this; } } }
 - lots of magic around making Key const
The most count of them may be solved without language modifying.
 - delete aa[key]
This case has gone one or two years ago. Now for the following code... int[int] aa; delete aa[5]; ... compiler writes me "Error: cannot delete type int"
 - lots of other small details (grep for Taarray in 
 src/expression.c)
We should start to try to find and solve them. As I see, we now we need only two language change requirements: opIndexCreate and AA literal overloading. The rest of the problems can be identified at the stage of parallel operation of both implementations.
May 29 2015
parent "Martin Nowak" <code dawg.eu> writes:
On Saturday, 30 May 2015 at 01:32:26 UTC, IgorStepanov wrote:
 - attributes
We will able to deprecate attribute violations in transitional version (with vtbl).
Yes, we'd have to deprecate attribute issues of the built-in AA before we can switch. Maybe that's already to disruptive.
 - literals (especially polysemous initializers, i.e. 
 ubyte[ubyte] aa = [0:1, 1:2])
Yes, this is the first main trouble.
We could possibly make the array of types polysemeous as well and deduce the type from the constructor argument.
 - implicit tail const conversion Val[Key] -> const(Val)[Key]
May be we may add "alias this"-es for all all those variants? Something like ... struct AA(K, V) { alias getCKeyMval this; alias getMKeyCval this; alias getCKeyCval this; property { ref AA!(const(K), V) getCKeyMval() { return *cast(typeof(return)*)&this; } ref AA!(K, const(V)) getMKeyCval() { return *cast(typeof(return)*)&this; } ref AA!(const(K), const(V)) getCKeyCval() { return *cast(typeof(return)*)&this; } } }
"overload" by return type? Maybe.
 We should start to try to find and solve them.
The list is pretty long, there are lots of unknowns. I'd rather choose an incremental approach that allows for intermediate failure.
May 30 2015
prev sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Friday, 29 May 2015 at 22:41:13 UTC, Martin Nowak wrote:
 2. What issues disallows us to implement full library AA?
 Except .stringof, .mangleof, and other compiler magic.
 I see only two issues: opIndexCreate and building aa from
 literals.
- error messages - attributes - literals (especially polysemous initializers, i.e. ubyte[ubyte] aa = [0:1, 1:2]) - implicit tail const conversion Val[Key] -> const(Val)[Key] - lots of magic around making Key const - delete aa[key] - lots of other small details (grep for Taarray in src/expression.c) This is a heavily used built-in type, we can't risk a rewrite that breaks lots of code.
Not sure how much this is a problem but implicit conversion from null may also be an issue: http://localhost/post/asvcbsvfcxznwypttojk 192.168.0.1
May 30 2015
next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Saturday, 30 May 2015 at 08:50:21 UTC, Vladimir Panteleev 
wrote:
 http://localhost/post/asvcbsvfcxznwypttojk 192.168.0.1
Sorry, working link: http://forum.dlang.org/post/asvcbsvfcxznwypttojk 192.168.0.1
May 30 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Saturday, 30 May 2015 at 08:51:31 UTC, Vladimir Panteleev 
wrote:
 On Saturday, 30 May 2015 at 08:50:21 UTC, Vladimir Panteleev 
 wrote:
 http://localhost/post/asvcbsvfcxznwypttojk 192.168.0.1
Sorry, working link: http://forum.dlang.org/post/asvcbsvfcxznwypttojk 192.168.0.1
We may say that AA!(K, V)* should be recognized as V[K] by compiler. However in this case we will found another problem: opIndexAssign will unable to allocate memory for the new AA instance, because it can't modify `this` pointer. Otherwise, implicit casting _from_ another type is a unsolvable task now. Please, remind, why we don't want to add possibility of implicit casting from another type (not as default constructor behaviour, of course)? Something like struct Foo { int a; static Foo opImplicitConstructFrom(T)(T val) if(is(T : int)) { return Foo(val); } }
May 30 2015
next sibling parent "IgorStepanov" <wazar mail.ru> writes:
 struct Foo
 {
     int a;
     static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))
     {
         return Foo(val);
     }
 }
void test(Foo foo, int i) { assert(foo.a == i); } test(42, 42); -> test(Foo.opImplicitConstructFrom(42), 42);
May 30 2015
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 30 May 2015 at 14:10:35 UTC, IgorStepanov wrote:
     static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))
I briefly mentioned this at the dconf and thinking about it a bit more, I think there's only two cases where we want implicit construction: function argument lists and function return values. (The syntax doesn't really matter, but I'd do it similar to C++ and just slap an implicit on a regular constructor). So: struct Foo { implicit this(typeof(null)) {} } Foo test() { return null; } Right now, that return null would say "cannot implicitly convert null to Foo". But since it is on a return statement and we have an implicit constructor, it would automatically rewrite that to return Foo(null); and be happy with it. Note that this does NOT change Foo foo = null; because that already works with a standard constructor today! Similarly, foo = null is handled with opAssign. So no change needed there. Anyway, the trickier case is function calls: void test(Foo) {} test(null); // should do test(Foo(null)); How does that interact with operator overloading? (I'd note that C++ does this so we could always borrow their rules too.) My proposal would be that if something matches exactly without implicit conversion, use that. Otherwise, try the implicit construction and issue an error if more than one match. This would work the same as arrays today: void a(int[]) {} void a(long[]) {} void a(typeof(null)) {} void main() { a(null); } That compiles. Comment the third line though and get: b.d(5): Error: b.a called with argument types (typeof(null)) matches both: b.d(1): b.a(int[] _param_0) and: b.d(2): b.a(long[] _param_0) So I think that's doable and shouldn't break any existing code as it is a new opt-in keyword. Just will have to watch for regression bugs... But that'd take care of the null problem with library AAs.... and I could use it to make my var type all the more wild :P
May 30 2015
next sibling parent "Meta" <jared771 gmail.com> writes:
On Saturday, 30 May 2015 at 15:24:49 UTC, Adam D. Ruppe wrote:
 On Saturday, 30 May 2015 at 14:10:35 UTC, IgorStepanov wrote:
    static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))
I briefly mentioned this at the dconf and thinking about it a bit more, I think there's only two cases where we want implicit construction: function argument lists and function return values. (The syntax doesn't really matter, but I'd do it similar to C++ and just slap an implicit on a regular constructor). So: struct Foo { implicit this(typeof(null)) {} } Foo test() { return null; } Right now, that return null would say "cannot implicitly convert null to Foo". But since it is on a return statement and we have an implicit constructor, it would automatically rewrite that to return Foo(null); and be happy with it. Note that this does NOT change Foo foo = null; because that already works with a standard constructor today! Similarly, foo = null is handled with opAssign. So no change needed there. Anyway, the trickier case is function calls: void test(Foo) {} test(null); // should do test(Foo(null)); How does that interact with operator overloading? (I'd note that C++ does this so we could always borrow their rules too.) My proposal would be that if something matches exactly without implicit conversion, use that. Otherwise, try the implicit construction and issue an error if more than one match. This would work the same as arrays today: void a(int[]) {} void a(long[]) {} void a(typeof(null)) {} void main() { a(null); } That compiles. Comment the third line though and get: b.d(5): Error: b.a called with argument types (typeof(null)) matches both: b.d(1): b.a(int[] _param_0) and: b.d(2): b.a(long[] _param_0) So I think that's doable and shouldn't break any existing code as it is a new opt-in keyword. Just will have to watch for regression bugs... But that'd take care of the null problem with library AAs.... and I could use it to make my var type all the more wild :P
This would also greatly improve Variant and Algebraic
May 30 2015
prev sibling parent "IgorStepanov" <wazar mail.ru> writes:
On Saturday, 30 May 2015 at 15:24:49 UTC, Adam D. Ruppe wrote:
 On Saturday, 30 May 2015 at 14:10:35 UTC, IgorStepanov wrote:
    static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))
I briefly mentioned this at the dconf and thinking about it a bit more, I think there's only two cases where we want implicit construction: function argument lists and function return values. (The syntax doesn't really matter, but I'd do it similar to C++ and just slap an implicit on a regular constructor).
What did people say about this idea?
May 30 2015
prev sibling parent Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 05/30/2015 10:50 AM, Vladimir Panteleev wrote:
 Not sure how much this is a problem but implicit conversion from null
 may also be an issue:
 http://localhost/post/asvcbsvfcxznwypttojk 192.168.0.1
Not in my proposal, b/c it's an explicit conversion that does allocate a translation wrapper. https://github.com/D-Programming-Language/druntime/pull/1282/files?diff=unified#diff-7f36fe9957b2e56c0c468548c4e1b0aaR167
Jun 20 2015
prev sibling next sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:
 Would be interesting to get some opinions on this.

 https://github.com/D-Programming-Language/druntime/pull/1282
BTW, I have one idea. We may declare the AA ABI: AA is a pointer to the next layout: __vtbl N bytes of data and __vtbl is a pointer to a struct: struct AAVTBL { size_t function() size; //returns the size of AA object: N + (AABTBL*).sizeof void* get(void* aa, somefields ) //another function } And it we teach compiler to use this ABI, we may say that any type which follows this ABI is a correct associative array. At the first stage, we may adapt the existing AA implementation to follow this ABI, and adapt the compiler to use it. After that, we will adble to write library AA (which also follows this ABI), which may be constructed as general D type, and casted to AA later.
May 25 2015
parent "Martin Nowak" <code dawg.eu> writes:
On Monday, 25 May 2015 at 23:39:18 UTC, IgorStepanov wrote:
 On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:
 Would be interesting to get some opinions on this.

 https://github.com/D-Programming-Language/druntime/pull/1282
BTW, I have one idea. We may declare the AA ABI: AA is a pointer to the next layout:
This is intended as temporary solution to simplify the transition to a library aa. Extending this conversion to other types for against the goal to replace the built-in AA.
May 27 2015
prev sibling parent reply "Mike" <none none.com> writes:
On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:
 Would be interesting to get some opinions on this.

 https://github.com/D-Programming-Language/druntime/pull/1282
For my own reasons, a library AA is most welcome: * separating library features from language features * making features optional and opt-in instead of opt-out * modularizing the language and runtime for pay-as-you-go implementations But, if you'll forgive my ignorance, what is the primary motivation for migrating to a library AA? Mike
May 29 2015
parent "Martin Nowak" <code dawg.eu> writes:
On Friday, 29 May 2015 at 11:16:27 UTC, Mike wrote:
 But, if you'll forgive my ignorance, what is the primary 
 motivation for migrating to a library AA?
- The current implementation uses runtime type information (TypeInfo) to compute hashes and compare keys. That's at least 2 virtual non-inlineable calls to lookup a value by an int key. Speedup is likely in the 1.5x-2x range. - The runtime interface is incorrectly attributed. - Small-key/value optimizations are hardly possible without statically knowing the types.
May 29 2015