Re: Rust-like collect in D
On Wed, 2016-10-12 at 21:15 -0400, Andrei Alexandrescu via Digitalmars- d-learn wrote: > On 10/06/2016 10:32 AM, Nordlöw wrote: > > Is there a concept in D similar to Rust's `collect`: > > > > https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.colle > > ct > > That's "make" in std.container. Is that what you're looking for? As > an > aside, "collect" is an awful abbreviation of "collection". -- Andrei I's say collect has an interesting history. Smalltalk used collect for what other called map. Various languages, including Groovy, continued this tradition. Now Rust and Java are using collect as a verb-like form, just as D uses make. collection would be wrong here. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Rust-like collect in D
On Thu, 2016-10-13 at 02:33 +, Meta via Digitalmars-d-learn wrote: > On Thursday, 13 October 2016 at 01:15:22 UTC, Andrei Alexandrescu > wrote: > > On 10/06/2016 10:32 AM, Nordlöw wrote: > > > Is there a concept in D similar to Rust's `collect`: > > > > > > https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.col > > > lect > > > > That's "make" in std.container. Is that what you're looking > > for? As an aside, "collect" is an awful abbreviation of > > "collection". -- Andrei > > I've always thought of it more as "collect the elements of the > iterator into a container". Java and Rust have gone the same route. collect is a terminal operation creating a data structure given a potentially infinite, lazily evaluated, stream. Rust uses iter for creating a stream from a data structure, Java uses stream or parallelstream. Java's parallelstream seems to be missing from Rust, but there is Rayon to provide a version. D's std.parallelism does something of this, but it needs more work to provide the tree-structured as well as scatter–gather internal parallelism models. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Rust-like collect in D
On Thursday, 13 October 2016 at 01:15:22 UTC, Andrei Alexandrescu wrote: On 10/06/2016 10:32 AM, Nordlöw wrote: Is there a concept in D similar to Rust's `collect`: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect That's "make" in std.container. Is that what you're looking for? As an aside, "collect" is an awful abbreviation of "collection". -- Andrei I've always thought of it more as "collect the elements of the iterator into a container".
Re: Rust-like collect in D
On 10/06/2016 10:32 AM, Nordlöw wrote: Is there a concept in D similar to Rust's `collect`: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect That's "make" in std.container. Is that what you're looking for? As an aside, "collect" is an awful abbreviation of "collection". -- Andrei
Re: opIndexDispatch?
On 10/10/2016 12:01 PM, Yuxuan Shui wrote: Hi, Why is there no opIndexDispatch for overloading a[x].func() ? I could not understand the question fully but would using an element proxy work? import std.stdio; struct ElementProxy { size_t index; void opDispatch(string name, Args...)(Args args) { writefln("%s() is called for index %s with args %s", name, index, [ args ]); } } struct A { auto opIndex(size_t index) { return ElementProxy(index); } } void main() { auto a = A(); a[0].foo(42); a[1].bar("hello", "world"); } Prints foo() is called for index 0 with args [42] bar() is called for index 1 with args ["hello", "world"] Ali
Re: opIndexDispatch?
On Wednesday, 12 October 2016 at 23:14:26 UTC, Jonathan M Davis wrote: opIndexUnary, opIndexAssign, and opIndexOpAssign exist to make it possible to do some basic operations on the result of foo[bar] without having to have opIndex return by ref, but assuming that you can return by ref, all of them could be done by having opIndex return by ref. No? If I want to mimics opIndex* by having opIndex return a ref. I would need to create a new entry every time opIndex is used to access a non-existent key, whether the return value is used as a lvalue or not. And opIndex* will solve this problem.
Re: overriding alias symbols
On Wednesday, 12 October 2016 at 22:14:32 UTC, Superstar64 wrote: ... Nevermind I just realized I can do this: --- abstract class MyAbstractClass { void myAbstractMethod(); } void defaultImplentation(T...) { } class MyClass : MyAbstractClass { override void myAbstractMethod() { return defaultImplentation!(); } }
Re: opIndexDispatch?
On Wednesday, October 12, 2016 22:45:28 Yuxuan Shui via Digitalmars-d-learn wrote: > On Monday, 10 October 2016 at 19:16:06 UTC, Jonathan M Davis > > wrote: > > On Monday, October 10, 2016 19:01:19 Yuxuan Shui via > > > > Digitalmars-d-learn wrote: > >> Hi, > >> > >> Why is there no opIndexDispatch for overloading a[x].func() ? > > > > There's opIndex for overloading a[x], and then you can call a > > function on the return value. If you want some kind of > > opDispatch on the return value, then the return type will need > > to implement opDispatch. > > > > - Jonathan M Davis > > The opIndex* overloads are used for handling the case where the > key is not already in the data structure, right? opIndex is for overriding the subscript operator so that you can do stuff like foo[bar]. What you actually make the function do is up to you. It could require that the element already be there. It could add the element if it's not there. It could even do something completely unrelated to indexing (though that would generally be considered bad practice). But aside from syntax, the requirements on it are largely just convention. It's good practice to make indexing act similarly to what you'd expect from a built-in type such as an array or associative array, but that's not actually enforced. opIndexUnary, opIndexAssign, and opIndexOpAssign exist to make it possible to do some basic operations on the result of foo[bar] without having to have opIndex return by ref, but assuming that you can return by ref, all of them could be done by having opIndex return by ref. If you were just wrapping an array or trying to mimic an array, then there's a decent chance that you'd just make opIndex return by ref and not overload the others, whereas in the case of something like an associative array, using opIndexAssign makes more sense, because the only way for opIndex to return by ref when opIndex creates the element is if it's default-initialized, whereas if opIndexAssign is used, it can just be created directly with the new value. If you're looking to be able to use opDispatch on the return value without returning by ref and while still affecting something within the object being indexed rather than just affecting the temporary that would be returned by opIndex, then you'll have to do something like return a type that has a pointer to the object being indexed and which implements opDispatch so that foo[bar].baz() uses opDispatch and still is able to acess foo via the pointer in the return value from foo[bar]. There is no opIndexDispatch to combine opIndex and opDispatch. - Jonathan M Davis
Re: overriding alias symbols
On Wednesday, 12 October 2016 at 22:46:14 UTC, Stefan Koch wrote: override void mixin (__traits(identifier, Method)) ... ? Doesn't work: test.d(8): Error: no identifier for declarator void test.d(9): Error: found '{' when expecting ')' test.d(10): Error: found '}' when expecting ';' I could make the whole function a mixin but I don't wanna hurt my compile times.
Re: overriding alias symbols
On Wednesday, 12 October 2016 at 22:14:32 UTC, Superstar64 wrote: I'm trying to use mixin templetes to provide generic default implementations. Something like this: --- abstract class MyAbstractClass { void myAbstractMethod(); } mixin template defaultImplentation(alias Method, T...) { override void Method() { } } class MyClass : MyAbstractClass { mixin defaultImplentation!(myAbstractMethod); } --- Anyone have any ideas? override void mixin (__traits(identifier, Method)) ... ?
Re: opIndexDispatch?
On Monday, 10 October 2016 at 19:16:06 UTC, Jonathan M Davis wrote: On Monday, October 10, 2016 19:01:19 Yuxuan Shui via Digitalmars-d-learn wrote: Hi, Why is there no opIndexDispatch for overloading a[x].func() ? There's opIndex for overloading a[x], and then you can call a function on the return value. If you want some kind of opDispatch on the return value, then the return type will need to implement opDispatch. - Jonathan M Davis The opIndex* overloads are used for handling the case where the key is not already in the data structure, right?
overriding alias symbols
I'm trying to use mixin templetes to provide generic default implementations. Something like this: --- abstract class MyAbstractClass { void myAbstractMethod(); } mixin template defaultImplentation(alias Method, T...) { override void Method() { } } class MyClass : MyAbstractClass { mixin defaultImplentation!(myAbstractMethod); } --- Anyone have any ideas?
Re: Continued looking at properties in D - interfaces and constraints
On Wednesday, October 12, 2016 20:40:57 mikey via Digitalmars-d-learn wrote: > OK I'm somewhat struggling with this concept. It is a bit weird. But consider class A { ... auto foo(int i) in { assert(i < 10); } out(r) { assert(r > 20); } body {...} ... } class B : A { ... override auto foo(int i) in { assert(i < 42); } out(r) { assert(r > 30); } body {...} ... } A a = func(); a.foo(5); a could be an A or a B. If it's an A, then the argument has to pass the in countract on A.foo, and the contract on B.foo doesn't matter, because it's not a B. And if a is actually a B, then the argument must _still_ pass A.foo's contract, because it's unknown from the caller's perspective whether it's an A or a B or some other class derived from A. B.foo can't have a tighter contract than A.foo, because that would violate the requirements of A.foo. If it were otherwise, if func() were changed to return a B instead of an A, the code would break even though it's using A's API and not B's. If B.foo required that i be less than 5, then suddenly code that worked with 6 would fail because of an in constraint that wasn't part of the API being used. So, tighter in contracts on derived class functions violate the contract of the base class function and cannot be allowed. However, B.foo _can_ have a looser in contract than A.foo, because if you're using it as an A, then everything that you can pass to A still works, and if you're using it as a B, and it accepts more than an A, so what? That's not a problem. You're using B's API and its requirements, not A's. So, by ||ing A.foo's and B.foo's in contracts, it allows B.foo to have a weaker contract, but it still requires that A.foo's contract be true. An out contract, on the other hand, is about guaranteeing that the result meets certain conditions. Whether the object is an A or a B, calling foo on an A reference must give a result that meets the out contract of A.foo. And B.foo's out contract cannot widen the conditions, otherwise, it would violate the out contract for A.foo. It can make them stronger, because it would still meet the requirements of A.foo, but it can't make them weaker. And if B.foo's out contract is stronger than A.foo's out contract, then when the object is a B, it has to meet both contracts, not just one of them, because if it just met A.foo's contract, then it would be violating the out contract on the function actually being called, but it still has to meet A.foo's contract, not just B.foo's contract, because if it doesn't, then when you the B is referred to be an A reference, it would be violating A's API. So, the out contracts get & together. Of course, you can always craft contracts that cause problems, but the compiler and runtime try and ensure that your contracts follow the logic required for a derived class to work correctly when referred to by a reference for a base class and while ensuring that the derived class does not violate the requirements of the API of the base class when the typeo of the reference is the derived class. > override @property void wage(uint wage) > in { > enforce(wage >= 10_000 && wage <= 40_000); > } body { > _wage = wage; > } > } Contracts are supposed to use assertions, since they're for checking code validity. And using exceptions doesn't buy you anything, because contracts get compiled out in -released just like the assertions do. You're just making it so that your function can't be nothrow (though there's an open bug - https://issues.dlang.org/show_bug.cgi?id=13123 - for the compiler not catching that a nothrow function can throw thanks to contracts). If you're trying to check the input and have the function throw so that the program can try and recover from the bad input rather than treating it as a logic error, then you need to throw an exception from inside the function body and not the in contract. - Jonathan M Davis
Re: Continued looking at properties in D - interfaces and constraints
On 10/12/2016 10:49 PM, mikey wrote: import std.exception; interface Widthy { @property inout(int) width() inout; @property void width(int width) in { enforce(width < 0); } } class Test : Widthy { private: int _w; public: @property inout(int) width() inout { return _w; } @property void width(int width) in { enforce(width < 0); } body { _w = width; } } void main() { import std.stdio; auto t = new Test; t.width = -1; writeln("width: ", t.width); // width: -1 // doesn't look right } The contract of the interface seems to see a wrong value: import std.stdio; interface Widthy { void width(int width) in { writeln(width); /* prints "2" */ assert(width > 0); } } class Test : Widthy { void width(int width) in { assert(width > 0); } body {} } void main() { auto t = new Test; t.width(-1); } I haven't checked closely, but there's issue 15984 which is titled "Interface contracts retrieve garbage instead of parameters". That's probably it. It's a regression in 2.071. https://issues.dlang.org/show_bug.cgi?id=15984
Re: Continued looking at properties in D - interfaces and constraints
On 10/12/2016 10:40 PM, mikey wrote: import std.exception; class Worker { private: uint _wage = 10_000; public: @property uint wage() { return _wage; } @property void wage(uint wage) in { enforce(wage >= 10_000 && wage <= 1_000_000_000); } body { _wage = wage; } } class WageSlave : Worker { private: uint _wage = 10_000; public: override @property uint wage() { return _wage; } override @property void wage(uint wage) in { enforce(wage >= 10_000 && wage <= 40_000); } body { _wage = wage; } } [...] void main() { [...] auto slave = new WageSlave; assertThrown( slave.wage = 9_999 ); assertThrown( slave.wage = 1_000_000_001 ); assertNotThrown( slave.wage = 10_000 ); assertNotThrown( slave.wage = 1_000_000_000 ); // BAD - no throw [...] } The behavior you expect would break substitutability [1]. Consider: void f(Worker w) { w.wage = 50_000; /* Contract of Worker says I can do this. */ } void main() { f(new Worker); /* Obviously ok. */ f(new WageSlave); /* Must work. A WageSlave object must be usable as a Worker object. */ } [1] https://en.wikipedia.org/wiki/Liskov_substitution_principle
Re: Continued looking at properties in D - interfaces and constraints
On Wednesday, 12 October 2016 at 20:49:40 UTC, mikey wrote: @property void width(int width) in { enforce(width < 0); } Arg! Stupid, I switched those around to enforces at the last minute, the sign should have been the other way round! Anyway the output is the same either way.
Re: Continued looking at properties in D - interfaces and constraints
Also, accepting that "in" contracts should be "or"ed, interfaces still seem broken to me: import std.exception; interface Widthy { @property inout(int) width() inout; @property void width(int width) in { enforce(width < 0); } } class Test : Widthy { private: int _w; public: @property inout(int) width() inout { return _w; } @property void width(int width) in { enforce(width < 0); } body { _w = width; } } void main() { import std.stdio; auto t = new Test; t.width = -1; writeln("width: ", t.width); // width: -1 // doesn't look right } It does however behave how you describe if you use inheritance with 2 classes, or if you change the interface property's contract to: @property void width(int width) in { assert(0); }
Re: Continued looking at properties in D - interfaces and constraints
On Wednesday, 12 October 2016 at 08:36:43 UTC, Jonathan M Davis wrote: That's exactly what it does. Having no contract is considered to be equivalent to having an empty contract. So, because an empty contract will never fail, not having an in contract in the base class (or interface) function is equivalent to not having any in contracts anywhere in the inheritance chain, which is pretty annoying. The ||ing and & done with in and out contracts and inheritance is critical to having contracts work correctly with inheritance. And in contracts work properly when each level declares one, but it probably would be better if having an in contract were illegal if the base class didn't have one, since then you'd at least avoid accidentally having an in contract that's pointless. out contracts shouldn't have any of these problems though, since they're &, and & with true doesn't change anything. Missing in contracts definitely is an easy way to introduce bugs into your contracts though. - Jonathan M Davis OK I'm somewhat struggling with this concept. As I see it the "in" contract can only place a limit on what values are valid to come in to the method. I could maybe see some questionable argument to make any contract for values coming into the method a subset of the previous valid values, but what you are describing is the opposite: that each contract has to be a superset of all the previous contracts for valid values! This seems limiting at best, but worse completely at odds with the concept of inheritance building from the most general to the most specific case. Say I have worker: import std.exception; class Worker { private: uint _wage = 10_000; public: @property uint wage() { return _wage; } @property void wage(uint wage) in { enforce(wage >= 10_000 && wage <= 1_000_000_000); } body { _wage = wage; } } class WageSlave : Worker { private: uint _wage = 10_000; public: override @property uint wage() { return _wage; } override @property void wage(uint wage) in { enforce(wage >= 10_000 && wage <= 40_000); } body { _wage = wage; } } class CEO : Worker { private: uint _wage = 1_000_000; public: override @property uint wage() { return _wage; } override @property void wage(uint wage) in { enforce(wage >= 1_000_000 && wage <= 1_000_000_000); } body { _wage = wage; } } void main() { auto worker = new Worker; assertThrown( worker.wage = 9_999 ); assertThrown( worker.wage = 1_000_000_001 ); assertNotThrown( worker.wage = 10_000 ); assertNotThrown( worker.wage = 1_000_000_000 ); auto slave = new WageSlave; assertThrown( slave.wage = 9_999 ); assertThrown( slave.wage = 1_000_000_001 ); assertNotThrown( slave.wage = 10_000 ); assertNotThrown( slave.wage = 1_000_000_000 ); // BAD - no throw auto ceo = new CEO; assertThrown( ceo.wage = 9_999 ); assertThrown( ceo.wage = 1_000_000_001 ); assertNotThrown( ceo.wage = 10_000 ); // BAD - no throw assertNotThrown( ceo.wage = 1_000_000_000 ); }
Re: Determining if a class has a template function
On Wednesday, 12 October 2016 at 16:57:50 UTC, Meta wrote: //A template function's .stringof is of the format name>()() //so match on the number of brackets to determine whether it's a template function or not enum isTemplateFunction = __traits(isTemplate, f) && fstr.balancedParens('(', ')') && (fstr.canFind("if") || fstr.count!(c => cast(bool)c.among!('(', ')')) == 4); Whoops, I forget to say that fstr is defined like this: enum fstr = f.stringof;
Re: Determining if a class has a template function
On Wednesday, 12 October 2016 at 16:29:22 UTC, Basile B. wrote: On Tuesday, 11 October 2016 at 20:17:19 UTC, Straivers wrote: I have a class T with a templated function foo(string name)(int, int, float) that will be mixed in via template, and I want to determine if that class has mixed it in such that foo(name = "bar"). How could I go about this? Thanks. eg: mixin template A(string name, Args...) { void foo(string fooName)(Args args) if (fooName == name) {} } template hasFoo(string name, A) { enum hasFoo = ??? } class B { mixin A!("mash", int, int, string); } For this particular example the following solution works: template A(string name, Args...) { void foo(string fooName)(Args args) if (fooName == name) {} } template hasFoo(string name, T, V...) { enum hasFoo = __traits(hasMember, T, "foo") && is(typeof(T.foo!name) == typeof(A!(name,V).foo!name)); } class B { mixin A!("mash", int, int, string); } unittest { static assert( hasFoo!("mash", B, int, int , string)); static assert( !hasFoo!("rash", B, int, uint , string)); } Now I can't say that I's generic enough to validate any members that's injected. Note well that it wouldn't work with a regular mixin template. You can also take a look at "std.traits.TemplateOf" There is also isTemplate (https://dlang.org/spec/traits.html#isTemplate). You can check first that the member exists and then check if it's a template (though this will pick up more than just template functions). There's also a *very* ugly hack you can do: //A template function's .stringof is of the format name>()() //so match on the number of brackets to determine whether it's a template function or not enum isTemplateFunction = __traits(isTemplate, f) && fstr.balancedParens('(', ')') && (fstr.canFind("if") || fstr.count!(c => cast(bool)c.among!('(', ')')) == 4);
Re: Determining if a class has a template function
On Tuesday, 11 October 2016 at 20:17:19 UTC, Straivers wrote: I have a class T with a templated function foo(string name)(int, int, float) that will be mixed in via template, and I want to determine if that class has mixed it in such that foo(name = "bar"). How could I go about this? Thanks. eg: mixin template A(string name, Args...) { void foo(string fooName)(Args args) if (fooName == name) {} } template hasFoo(string name, A) { enum hasFoo = ??? } class B { mixin A!("mash", int, int, string); } For this particular example the following solution works: template A(string name, Args...) { void foo(string fooName)(Args args) if (fooName == name) {} } template hasFoo(string name, T, V...) { enum hasFoo = __traits(hasMember, T, "foo") && is(typeof(T.foo!name) == typeof(A!(name,V).foo!name)); } class B { mixin A!("mash", int, int, string); } unittest { static assert( hasFoo!("mash", B, int, int , string)); static assert( !hasFoo!("rash", B, int, uint , string)); } Now I can't say that I's generic enough to validate any members that's injected. Note well that it wouldn't work with a regular mixin template. You can also take a look at "std.traits.TemplateOf"
Re: vibe.d HTMLLogger
On Wednesday, 12 October 2016 at 11:54:14 UTC, Chris wrote: Why does FileLogger work while HTMLLogger crashes on the same thing? I've had a look at the source code, but couldn't find anything. It happens with vibe.d `0.7.30-beta1` and `0.7.29` alike (haven't tested lower versions). [Test code] auto logLine = LogLine(); logLine.level = LogLevel.info; // Fine auto l = new FileLogger("log/logger_test.log"); l.minLevel = LogLevel.info; l.beginLine(logLine); l.put("Hello!"); l.endLine(); htmlLogger = new HTMLLogger("log/logger_test.html"); htmlLogger.minLevel = LogLevel.info; // crashes here (at `beginLine`), if removed it works. htmlLogger.beginLine(logLine); htmlLogger.put("Hello!"); htmlLogger.endLine(); The answer is that `HTMLLogger` needs to be given the time in the `LogLine` struct, else it fails. The time stamp is not auto generated. I completely overlooked that. Here's the culprit: cf. m_logFile.writef(`%s`, msg.time.toISOExtString()); https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/core/log.d#L363
Re: Anonymous class
On 10/12/2016 01:56 PM, tcak wrote: I feel like I remember that this was added to D a while ago, but I am not sure. Is it possible to create anonymous classes? public interface Runnable{ void run(); } runIt( new Runnable(){ void run(){ /* do stuff */ } }); runIt(new class Runnable { void run() { /* do stuff */ }}); https://dlang.org/spec/class.html#anonymous
Re: Anonymous class
On Wednesday, 12 October 2016 at 11:56:21 UTC, tcak wrote: I feel like I remember that this was added to D a while ago, but I am not sure. Is it possible to create anonymous classes? public interface Runnable{ void run(); } runIt( new Runnable(){ void run(){ /* do stuff */ } }); I want to do this without making the things any complex. Hmm. Yeah, after playing around, and some clues from net search. I found it. runIt( new class Runnable{ void run(){ /* do stuff */ } });
Anonymous class
I feel like I remember that this was added to D a while ago, but I am not sure. Is it possible to create anonymous classes? public interface Runnable{ void run(); } runIt( new Runnable(){ void run(){ /* do stuff */ } }); I want to do this without making the things any complex.
vibe.d HTMLLogger
Why does FileLogger work while HTMLLogger crashes on the same thing? I've had a look at the source code, but couldn't find anything. It happens with vibe.d `0.7.30-beta1` and `0.7.29` alike (haven't tested lower versions). [Test code] auto logLine = LogLine(); logLine.level = LogLevel.info; // Fine auto l = new FileLogger("log/logger_test.log"); l.minLevel = LogLevel.info; l.beginLine(logLine); l.put("Hello!"); l.endLine(); htmlLogger = new HTMLLogger("log/logger_test.html"); htmlLogger.minLevel = LogLevel.info; // crashes here (at `beginLine`), if removed it works. htmlLogger.beginLine(logLine); htmlLogger.put("Hello!"); htmlLogger.endLine();
Re: How to do "inheritance" in D structs
On Wednesday, 12 October 2016 at 02:33:20 UTC, lobo wrote: On Wednesday, 12 October 2016 at 02:18:47 UTC, TheFlyingFiddle wrote: On Wednesday, 12 October 2016 at 01:22:04 UTC, lobo wrote: Hi, I'm coming from C++ and wondered if the pattern below has an equivalent in D using structs. I could just use classes and leave it up to the caller to use scoped! as well but I'm not sure how that will play out when others start using my lib. Thanks, lobo module A; class Base1 { int ival = 42; } class Base2 { int ival = 84; } module B; class S(ABase) : ABase { string sval = "hello"; } module C; import A; import B; void main() { auto s= scoped!(S!Base1); // scoped!(S!Base2) } You could use "alias this" to simulate that type of inheritence. module A; struct Base1 { int ival = 42; } module B; struct Base2 { int ival = 84; } module C; import A, B; struct S(Base) if(is(Base == struct)) { Base base; alias base this; string sval = "Hello "; } void foo(ref ABase base) { base.ival = 32; } void main() { S!Base1 a; S!Base2 b; writeln(a.sval, a.ival); writeln(b.sval, b.ival); foo(a); writeln(a.sval, a.ival); } This approach works nicely although it feels clumsy but that's probably just because I'm so used to C++. It also handles private members as I'd expect, i.e. they're not accessible outside module scope through the alias struct instance, but there is no protected. Protected appears to behave the same way as private. I think I can live with that because I usually try to avoid protected anyway. Thanks, lobo Note that alias this is not inheritance, it's subtyping. What happens when doing: struct P { int val = 42; } struct S { P p; alias p this; } assert(S().val == 42); is that S tries to find “ this.val ”. First it looks in its scope without success. Then it uses the alias to transform “ this.val ” into “ p.val ”, but the type S isn't linked to the type P. When using attributes of p you are really dealing with a real object of type P. It also means that implicit conversion of S in P will just copy the p member: struct P { int val = 42; } struct S { P p; alias p this; int val = 1234; } void main(string[] args) { P p = S(); assert(p.val == 42); } Assert this is a great feature but it has to be well understood.
Re: Continued looking at properties in D - interfaces and constraints
On Sunday, October 09, 2016 14:06:42 Antonio Corbi via Digitalmars-d-learn wrote: > I think that the compiler assumes that its empty contract is always true. That's exactly what it does. Having no contract is considered to be equivalent to having an empty contract. So, because an empty contract will never fail, not having an in contract in the base class (or interface) function is equivalent to not having any in contracts anywhere in the inheritance chain, which is pretty annoying. The ||ing and & done with in and out contracts and inheritance is critical to having contracts work correctly with inheritance. And in contracts work properly when each level declares one, but it probably would be better if having an in contract were illegal if the base class didn't have one, since then you'd at least avoid accidentally having an in contract that's pointless. out contracts shouldn't have any of these problems though, since they're &, and & with true doesn't change anything. Missing in contracts definitely is an easy way to introduce bugs into your contracts though. - Jonathan M Davis
Re: Continued looking at properties in D - interfaces and constraints
On Wednesday, 12 October 2016 at 06:20:05 UTC, mikey wrote: On Sunday, 9 October 2016 at 14:06:42 UTC, Antonio Corbi wrote: 1. Inheritance with contracts is evaluated in a special way, 'in contracts' in the base and derived method (property) are or-ed, so if one of them passses, the contract is believed to have succeeded. As you don't have a contract in the base-method: "@property void width(int width)", I think that the compiler assumes that its empty contract is always true. Doesn't sound right to me. "Or"ing contracts with different inherited methods can't possibly be a feature. I'll create a bug report for it. Hi Mikey, It's the way DbC (Design by Contract) works, have a look at point 8 in https://www.eiffel.com/values/design-by-contract/introduction/ Antonio
Re: Continued looking at properties in D - interfaces and constraints
On Wednesday, 12 October 2016 at 06:20:05 UTC, mikey wrote: On Sunday, 9 October 2016 at 14:06:42 UTC, Antonio Corbi wrote: 1. Inheritance with contracts is evaluated in a special way, 'in contracts' in the base and derived method (property) are or-ed, so if one of them passses, the contract is believed to have succeeded. As you don't have a contract in the base-method: "@property void width(int width)", I think that the compiler assumes that its empty contract is always true. Doesn't sound right to me. "Or"ing contracts with different inherited methods can't possibly be a feature. I'll create a bug report for it. https://dlang.org/spec/contracts.html#in_out_inheritance
Re: How to do "inheritance" in D structs
On 2016-10-12 03:22, lobo wrote: Hi, I'm coming from C++ and wondered if the pattern below has an equivalent in D using structs. I could just use classes and leave it up to the caller to use scoped! as well but I'm not sure how that will play out when others start using my lib. Thanks, lobo module A; class Base1 { int ival = 42; } class Base2 { int ival = 84; } module B; class S(ABase) : ABase { string sval = "hello"; } module C; import A; import B; void main() { auto s= scoped!(S!Base1); // scoped!(S!Base2) } Depending on what you need, any alternative to structs and "alias this" would be to use structs with template mixins [1]: mixin template Base1() { int ival = 42; } struct S(ABase) { mixin ABase; } What's in the struct will take precedence of what's in the template mixin. It's also possible to mix in several templates. [1] http://dlang.org/spec/template-mixin.html -- /Jacob Carlborg
Re: How to do "inheritance" in D structs
On 2016-10-12 04:33, lobo wrote: This approach works nicely although it feels clumsy but that's probably just because I'm so used to C++. It also handles private members as I'd expect, i.e. they're not accessible outside module scope through the alias struct instance, but there is no protected. Protected appears to behave the same way as private. I think I can live with that because I usually try to avoid protected anyway. I only expect "protected" to work with real inheritance, i.e. classes. Note that there's "package" protection attribute as well. -- /Jacob Carlborg
Re: Continued looking at properties in D - interfaces and constraints
On Sunday, 9 October 2016 at 14:06:42 UTC, Antonio Corbi wrote: 1. Inheritance with contracts is evaluated in a special way, 'in contracts' in the base and derived method (property) are or-ed, so if one of them passses, the contract is believed to have succeeded. As you don't have a contract in the base-method: "@property void width(int width)", I think that the compiler assumes that its empty contract is always true. Doesn't sound right to me. "Or"ing contracts with different inherited methods can't possibly be a feature. I'll create a bug report for it.