July 26, 2015
Alix Pexton <alix.DOT.pexton@gmail.DOT.com> wrote:
> On 25/07/2015 9:48 PM, Walter Bright wrote:
> 
>> Unfortunately, Bruce Eckel's seminal article on it
>> http://www.mindview.net/Etc/Discussions/CheckedExceptions has
>> disappeared. Eckel is not a Java code monkey, he wrote the book Thinking
>> In Java
>> http://www.amazon.com/gp/product/0131002872/
>> 
> 
> 
> https://web.archive.org/web/20150515072240/http://www.mindview.net/Etc/Discussions/CheckedExceptions

This is article not convincing at all. His argument is basically "Most programmers are sloppy and tend to catch and ignore checked exceptions."

The same programmers that do this will just catch all RuntimeExceptions at
top level, write a log entry and proceed.
That's actually not much better and certainly not correct error handling.

Tobi
July 26, 2015
On 7/26/2015 8:20 AM, Andrei Alexandrescu wrote:
> On 7/25/15 6:54 PM, deadalnix wrote:
>> On Saturday, 25 July 2015 at 10:05:35 UTC, Tofu Ninja wrote:
>>> On Saturday, 25 July 2015 at 09:40:52 UTC, Walter Bright wrote:
>>>> if the template body uses an interface not present in the type and
>>>> not checked for in the constraint, you will *still* get a compile
>>>> time error.
>>>
>>> But only if the template gets instantiated with a bad type. Unit tests
>>> don't catch every thing and have to be written properly. A proper type
>>> system should catch it.
>>
>> This unitest argument is becoming ridiculous. Unless some strong
>> argument is brought to the table that this differs from the "dynamic
>> typing is not a problem if you write unitest" we we all should know is
>> bogus at this point, it can't be taken seriously.
>
> To me that's self understood. Run time is fundamentally different from
> everything preceding it. -- Andrei

Unit tests are also not exclusively about runtime. Using a unit test to instantiate a template is a compile time test.
July 26, 2015
On Sunday, 26 July 2015 at 16:39:23 UTC, jmh530 wrote:
> My biggest problem with your point about including everything in the top-level is that if you make a change to the constraints in the bottom level then you have to remember to make the changes everywhere else.

Well, that's pretty much exactly why Walter is trying to say that it's the same problem as checked exceptions. Changing something lower in the chain forces you to change everything higher in the chain - and often, stuff higher in the chain isn't written by the same person or organization as the stuff lower in the chain. If we did what some folks are suggesting and make it so that the compiler gave an error if a template constraint failed to cover all of its sub-constraints (which would probably require using concepts), then changing the function lower in the chain would outright break all of the code higher in the chain, making it even more like checked exceptions. But even without that enforcement, we have a maintenance problem if the lower level constraints need to be propagated. If the constraints almost never change, then it won't necessarily be a big deal, but as code is updated and improved, then it could be a much bigger one.

For a publicly available library like Phobos, the solution may simply be that the template constraints of functions in the public API can only ever be made less strict rather than more strict so that they don't stop working with any existing code or cause other functions up the chain to have to tighten their template constraints as well. But with all of the inference and conditional compilation that you get in D code, maybe even reducing the restrictions would cause problems in some cases - especially if something like __traits(compiles, ...) is used in template constraints, because that change could potentially make it so that overloads start conflicting (or just change) in higher level functions and thus break code. Though given how much you can do with metaprogramming in D, pretty soon changing _anything_ risks breaking code, so I don't know how much we should really worry about that. If you're doing stuff that involves that much type introspection, the odds of your code breaking with changes to the libraries you're using are high enough that it's probably not reasonable to expect that it won't break anyway.

In any case, I suppose that we'll just have to wait and see how much a problem this will really become, but I don't think attempting to keep the higher level constraints in line with the lower level ones is as bad as doing something like concepts where it's forced. At least with what we have, the worst you normally get is an error inside of a template instead of at the outer template constraint. And if someone doesn't want to try and propagate the template constraints, they don't have to - they just then have to deal with error messages being inside of the templated function (or inside of templated functions that gets called by that function - either directly or indirectly) - and if we improve the error messages enough, then that won't be so bad. So, we have a potential maintenance problem here, but it's not one that's generally going to be from broken code so much as reporting the error at a point other than the one where folks want to see it.

- Jonathan M Davis
July 26, 2015
On Sunday, 26 July 2015 at 15:19:06 UTC, Andrei Alexandrescu wrote:
> Probably that's the root of all disagreement. So we have template writing time, template instantiation time, and just run time. I think template instantiation time is a lot "closer" to template writing time than run time. -- Andrei

It is closer, but it doesn't matter for the argument being made.

You have some code that expect its argument to conform to some API. Be it dynamically typed code (which will blow up at runtime, or worse, do random shit) or template code (which will blow up at instanciation time, or worse, do random shit).

The problem being fundamentally the same, arguments going for or against one go for the other.

July 26, 2015
On Sunday, 26 July 2015 at 15:33:59 UTC, Andrei Alexandrescu wrote:
> On 7/26/15 5:04 AM, deadalnix wrote:
>> On Sunday, 26 July 2015 at 00:18:14 UTC, Walter Bright wrote:
>>> On 7/25/2015 3:59 PM, deadalnix wrote:
>>>> On Saturday, 25 July 2015 at 12:05:12 UTC, Andrei Alexandrescu wrote:
>>>>> Well at least all paths must be compiled. You wouldn't ship
>>>>> templates that
>>>>> were never instantiated just as much as you wouldn't ship any code
>>>>> without
>>>>> compiling it. We've had a few cases in Phobos a while ago of
>>>>> templates that
>>>>> were never instantiated, with simple compilation errors when people
>>>>> tried to
>>>>> use them. -- Andrei
>>>>
>>>> That is an instance of happy case testing. You test that what you
>>>> expect to work
>>>> work. You can't test that everything that is not supposed to work do
>>>> not, or
>>>> that you don't rely on a specific behavior of the thing you are testing.
>>>>
>>>
>>> Um, testing all paths is not happy case testing.
>>
>> You test all execution path, not all "instantiation path". Consider
>> this, in a dynamically typed language, you can have a function that
>> accept a string and do something with it. You can write unit tests to
>> check it does the right thing with various strings and make sure it
>> execute all path.
>>
>> Yet, what happen when it is passed an int ? a float ? an array ? an
>> object ? Probably random shit.
>>
>> Same here, but at instantiation time.
>
> No, you are very wrong here. I am sorry! Instantiation testing is making sure that syntactic conformance is there. Semantic conformance cannot be tested during compilation (big difference) and can be partially verified dynamically.
>
> This whole conflation with dynamic typing/unittesting is inappropriate and smacks of https://en.wikipedia.org/wiki/Argument_from_analogy. If you have a point, make it stand on its own.
>
>
> Andrei

It is not an analogy. The dynamic typing is not a problem that is used as example or something. This is fundamentally the same problem. I've made that point earlier, and I stand by it.

Claiming it is inappropriate do not make it so. Once again, statements do not constitute good arguments. If you make a good point that they differs in such a way that I missed then you basically ends the argument.

July 26, 2015
On Sunday, 26 July 2015 at 19:54:28 UTC, Walter Bright wrote:
> Unit tests are also not exclusively about runtime. Using a unit test to instantiate a template is a compile time test.

Yes, it test the instantiation to some extent. It tests that the instantiate works granted you pass it what is expected.

It does not test that the instantiation will fail if you pass it anything else, or worse, do random unexpected stuff.

The problem is the exact same as for dynamic typing and unitests. A dynamically typed function that expect a string can be test exhaustively with warious string passed as arguments. Still, none knows what happen when passed an int, float, array, object or whatever. Worse, it is either going to blow up in some unexpected way or not explode and do random stuff.

The same way, instantiate your template with something it doesn't expect and you get absurdly complex errors (and it is getting worse as phobos get more and more "enterprise" with Foo forwarding to FooImpl and 25 different helpers).

The problem is the same, will it fail at call site/instanciation site with "I expected X you gave me Y" or will it fail randomly somewhere down the road in some unrelated part of the code, or worse, not fail at all when it should have ?

July 26, 2015
On 7/26/15 3:54 PM, Walter Bright wrote:
> On 7/26/2015 8:20 AM, Andrei Alexandrescu wrote:
>> On 7/25/15 6:54 PM, deadalnix wrote:
>>> On Saturday, 25 July 2015 at 10:05:35 UTC, Tofu Ninja wrote:
>>>> On Saturday, 25 July 2015 at 09:40:52 UTC, Walter Bright wrote:
>>>>> if the template body uses an interface not present in the type and
>>>>> not checked for in the constraint, you will *still* get a compile
>>>>> time error.
>>>>
>>>> But only if the template gets instantiated with a bad type. Unit tests
>>>> don't catch every thing and have to be written properly. A proper type
>>>> system should catch it.
>>>
>>> This unitest argument is becoming ridiculous. Unless some strong
>>> argument is brought to the table that this differs from the "dynamic
>>> typing is not a problem if you write unitest" we we all should know is
>>> bogus at this point, it can't be taken seriously.
>>
>> To me that's self understood. Run time is fundamentally different from
>> everything preceding it. -- Andrei
>
> Unit tests are also not exclusively about runtime. Using a unit test to
> instantiate a template is a compile time test.

YES! For templates unittests have a dual role. -- Andrei
July 26, 2015
On Sunday, 26 July 2015 at 18:13:30 UTC, Tobias Müller wrote:
> Alix Pexton <alix.DOT.pexton@gmail.DOT.com> wrote:
>> On 25/07/2015 9:48 PM, Walter Bright wrote:
>> 
>>> Unfortunately, Bruce Eckel's seminal article on it
>>> http://www.mindview.net/Etc/Discussions/CheckedExceptions has
>>> disappeared. Eckel is not a Java code monkey, he wrote the book Thinking
>>> In Java
>>> http://www.amazon.com/gp/product/0131002872/
>>> 
>> 
>> 
>> https://web.archive.org/web/20150515072240/http://www.mindview.net/Etc/Discussions/CheckedExceptions
>
> This is article not convincing at all. His argument is basically "Most programmers are sloppy and tend to catch and ignore checked exceptions."
>

No it is that checked Exception encourage this behavior.

Ultimately, checked exception are a failure as they completely break encapsulation. Let's say you have a logger interface. Some of its implementation will just send the log to Dave Null, some write it in a file, some will send it over the network to some tailor, and so on. The class of error that arise from each is completely different and cannot be listed exhaustively at the interface level in any meaningful way.

> The same programmers that do this will just catch all RuntimeExceptions at
> top level, write a log entry and proceed.
> That's actually not much better and certainly not correct error handling.
>
> Tobi

This is often the only meaningful thing you have to do with an exception anyway.

July 26, 2015
On Sunday, 26 July 2015 at 03:42:22 UTC, Walter Bright wrote:
> On 7/25/2015 3:28 PM, deadalnix wrote:
>> Also, argument from ignorance is hard to maintain when the thread is an actual
>> feedback from experience.
>
> You say that interfaces do the same thing. So please show how it's done with the example I gave:
>
>     int foo(T: hasPrefix)(T t) {
>        t.prefix();    // ok
>        bar(t);        // error, hasColor was not specified for T
>     }
>
>     void bar(T: hasColor)(T t) {
>        t.color();
>     }

I'm not sure what is the problem here.
July 26, 2015
On 7/26/2015 3:53 PM, deadalnix wrote:
> On Sunday, 26 July 2015 at 19:54:28 UTC, Walter Bright wrote:
>> Unit tests are also not exclusively about runtime. Using a unit test to
>> instantiate a template is a compile time test.
>
> Yes, it test the instantiation to some extent. It tests that the instantiate
> works granted you pass it what is expected.
>
> It does not test that the instantiation will fail if you pass it anything else,
> or worse, do random unexpected stuff.

If the template constraint is 'isInputRange', and you pass it an 'InputRange' that is nothing beyond an input range, and it compiles, it is JUST AS GOOD as Rust traits, without needing to add 'isInputRange' to every template up the call tree.

In fact, I do just this in my D dev projects. I have a set of mock ranges that match each of the range types.


> The problem is the exact same as for dynamic typing and unitests. A dynamically
> typed function that expect a string can be test exhaustively with warious string
> passed as arguments. Still, none knows what happen when passed an int, float,
> array, object or whatever. Worse, it is either going to blow up in some
> unexpected way or not explode and do random stuff.

Flatly no, it is not at all the same. Dynamic typing systems do not have constraints. Furthermore, dynamic typed languages tend to do random s**t when presented with the wrong type rather than fail. (Such as concatenating strings when the code was intended to do an arithmetic add.) D does not, it presents the user with a compilation error.


> The same way, instantiate your template with something it doesn't expect and you
> get absurdly complex errors (and it is getting worse as phobos get more and more
> "enterprise" with Foo forwarding to FooImpl and 25 different helpers).

This is incorrect. In my D project development, when I send the wrong thing, I get a list of the template instantiation stack. The bottom gives the method not found, and the stack gives how it got there. I find it adequate in that it doesn't take much effort to figure out where things went wrong.

BTW, when you discover that a constraint is wrong on a Phobos template, please file a bug report on it.


> The problem is the same, will it fail at call site/instanciation site with "I
> expected X you gave me Y" or will it fail randomly somewhere down the road in
> some unrelated part of the code, or worse, not fail at all when it should have ?

If the constraint is InputRange, and the body assumes ForwardRange, and I pass it a ForwardRange, and it works, how is that 'worse'?