1 import std.stdio; 2 import core.exception; 3 4 interface I { 5 void test(int a) 6 in(a > 20); 7 } 8 9 class Implementation : I { 10 override void test(int a) 11 // without this pattern, the interface 12 // contract gets ignored! So we want to 13 // specify we will use it, without repeating 14 // it... which our new pattern allows: 15 in(false) // use interface's contract 16 { 17 writeln("implementation called"); 18 } 19 } 20 21 void main() { 22 try { 23 auto d = new Implementation(); 24 d.test(30); // OK by interface contract 25 d.test(10); // and now this throws too 26 } catch(AssertError ae) { 27 writeln("correctly thrown with interface!"); 28 } 29 }
Core D Development Statistics
In the community
Community announcements
See more at the announce forum.
What Adam is working on
I started arsd.webview, a port of a wrapper around the webviews commonly found in operating systems. I probably won't finish it until the end of the month, even though it isn't a whole lot of code (by design - I don't want a huge package to distribute to use it).
Tip of the Week
D has a feature called contract programming, which lets you attach in and out statements to functions (and other things, but that's what I want to focus on right now) to assert various conditions about how your function is called and what it returns. Unlike plain assert statements in function bodies though, contracts work with inheritance. Though the specifics can be confusing.
In that case, we see the base class threw due to the invalid argument, but not with the derived class. Are contracts inherited?
The answer is "yes", but they are easily ignored due to the application of the Liskov substitution principle.
D applies the "loosen params, tighten returns" guideline by implementing contracts and inheritance as Derived in || Base in and then Derived out && Base out. See: https://dlang.org/spec/contracts.html#in_out_inheritance
If you don't specify a contract, D treats it as always true, in other words, the contract accepts anything. Thus, in the example above, Derived in == true, so the overall thing is true || a > 20... and now we can see why it always passes with the derived class.
Can we explicitly indicate that we want to use the parent class' contract? Well, consider that X || B statement again... if X is true, B is skipped. But if X is false, B is always used and determines the overall condition. Thus, we get a new pattern:
Let's apply it to the test:
The syntax is a little bit weird - in(false) might take some getting used to - but if you know the reasoning above it makes sense, and if you think of the contracts in an overridden function as being "expand the input", in(false) could perhaps mean "do not expand the input".
It doesn't *quite* mean that all the time, which is why I bolded "overridden function" there. If you are using the override keyword, you know there is a base method; this is statically guaranteed!
If it isn't overridden, of course, there is no parent to fallback on, so in(false) there would always fail! So don't use this pattern without override so you get that guarantee that there actually is something to inherit.
BTW I didn't realize this until today, but the body or the do keyword on function bodies are unnecessary using the newer-style short contract syntax! Like I did in my examples here, I think it looks pretty OK.
Bonus link
I wrote a little bit about output ranges on stack overflow this week too: https://stackoverflow.com/a/59116772/1457000