November 09, 2012
On Thu, 08 Nov 2012 21:10:55 -0800
Walter Bright <newshound2@digitalmars.com> wrote:
> 
> Many algorithms (at least the ones in Phobos do) already do a check to ensure the inputs are the correct kind of range. I don't think you'll get very far trying to use a range that isn't a range.
> 

It can't check semantics. If something "looks" like a range function,
but wasn't written with the explicit intent of actually being one, then
it's a crapshoot as to whether the semantics actually conform. But
the ducktyping D does do will go and blindly assume.


November 09, 2012
On Thu, 08 Nov 2012 21:24:49 -0800
Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Thursday, November 08, 2012 21:10:55 Walter Bright wrote:
> > Many algorithms (at least the ones in Phobos do) already do a check to ensure the inputs are the correct kind of range. I don't think you'll get very far trying to use a range that isn't a range.
> > 
> > Of course, you can always still have bugs in your range implementation.
> 
> Given that a range requires a very specific set of functions, I find it highly unlikely that anything which isn't a range will qualify as one. It's far more likely that you screw up and a range isn't the right kind of range because one of the functions wasn't quite right.
> 
> There is some danger in a type being incorrectly used with a function when that function requires and tests for only one function, or maybe when it requires two functions. But I would expect that as more is required by a template constraint, it very quickly becomes the case that there's no way that any type would ever pass it with similarly named functions that didn't do the same thing as what they were expected to do. It's just too unlikely that the exact same set of function names would be used for different things, especially as that list grows. And given that ranges are a core part of D's standard library, I don't think that there's much excuse for having a type that has the range functions but isn't supposed to be a range. So, I really don't see this as a problem.
> 

Looking at one set of interfaces in isolation, sure the chances might be low. (Just like the chances of name collisions when hygeine is lacking, and yet we thankfully have a real module system, instead of C's clumsy "Well, it should usually work ok!" garbage.) But it's a terrible precedent. Scale things up, use ducks as common practice, and all of a sudden you're right back into the same old land of "no-hygeine". Bad, sloppy, lazy precedent. AND the presumed benefit of the duckness is minimal at best. Just not a good design, it makes all the wrong tradeoffs.

November 09, 2012
On Friday, November 09, 2012 01:44:51 Nick Sabalausky wrote:
> On Thu, 08 Nov 2012 21:10:55 -0800
> 
> Walter Bright <newshound2@digitalmars.com> wrote:
> > Many algorithms (at least the ones in Phobos do) already do a check to ensure the inputs are the correct kind of range. I don't think you'll get very far trying to use a range that isn't a range.
> 
> It can't check semantics. If something "looks" like a range function,
> but wasn't written with the explicit intent of actually being one, then
> it's a crapshoot as to whether the semantics actually conform. But
> the ducktyping D does do will go and blindly assume.

True, but how likely is it that a type will define all of the necessary range functions and _not_ supposed to be a range? The type must define a specific set of functions, and those functions must compile with at isInputRange at minimum, which checks more than just the function names, and the more complex the range required, the more functions are required and the more specific the tests are (e.g. while isInputRange doesn't test the type of front, isBidirectionalRange does test that front and back have the same type). The odds of accidentally matching isInputRange are already low, but they dwindle to nothing pretty darn quickly as the type of range is more complex, simply because the number of functions and the tests made on them increase to the point that there's pretty much no way that anything will ever accidentally pass them without being intended to be a range.

I just don't think that the odds of anything accidentally passing the range traits - even isInputRange - are very high at all. And given that ranges are part of the standard library, I don't think that there's really any excuse for anyone using the names of range functions for something else, not more than one or two of them at once anyway. So, I really think that any worries about this are unfounded.

- Jonathan M Davis
November 09, 2012
On 11/9/12, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> Yeah, that's one major missing feature from D/Phobos/etc.: a mixin template called EliminateBugs that will fix all your program's bugs for you. I think that should be the next top priority on D's to-do list! ;-)

Considering you can do a string import of the module you're in (provided the -J switch), and the fact that Pegged works at compile-time, that wouldn't be a far-fetched dream at all. :p
November 09, 2012
On 2012-11-09 07:20, H. S. Teoh wrote:

> Well, unittests are a runtime check, and they don't *guarantee*
> anything. (One could, in theory, write a pathological pseudo-range that
> passes basic unittests but fail to behave like a range in some obscure
> corner case. Transient ranges would fall under that category, should we
> decide not to admit them as valid ranges. :-))
>
> But of course that's just splitting hairs.

But since we do have a language with static typing we can at least do our best to try at catch as many errors as possible at compile time. We don't want to end up as a dynamic language and testing for types in the unit tests.

-- 
/Jacob Carlborg
November 09, 2012
On Friday, November 09, 2012 01:53:40 Nick Sabalausky wrote:
> Looking at one set of interfaces in isolation, sure the chances might be low. (Just like the chances of name collisions when hygeine is lacking, and yet we thankfully have a real module system, instead of C's clumsy "Well, it should usually work ok!" garbage.) But it's a terrible precedent. Scale things up, use ducks as common practice, and all of a sudden you're right back into the same old land of "no-hygeine". Bad, sloppy, lazy precedent. AND the presumed benefit of the duckness is minimal at best. Just not a good design, it makes all the wrong tradeoffs.

As long as your template constraints requires more than a couple of functions and actually tests much of anything about what those functions return or what arguments can be passed to them, I find it very unlikely that anything will accidentally pass them. Too many coincidences would be required to end up with a set of functions that matched when they weren't supposed to . It's only likely to be problem if you're checking only one or two functions and don't check much beyond their existence. It just doesn't take very many checks before it's highly unlikely for anyone to have created a type with functions with the same names and whose signatures are close enough to pass a template constraint when they're not supposed to.

- Jonathan M Davis
November 09, 2012
On Friday, November 09, 2012 08:21:38 Jacob Carlborg wrote:
> On 2012-11-09 07:20, H. S. Teoh wrote:
> > Well, unittests are a runtime check, and they don't *guarantee* anything. (One could, in theory, write a pathological pseudo-range that passes basic unittests but fail to behave like a range in some obscure corner case. Transient ranges would fall under that category, should we decide not to admit them as valid ranges. :-))
> > 
> > But of course that's just splitting hairs.
> 
> But since we do have a language with static typing we can at least do our best to try at catch as many errors as possible at compile time. We don't want to end up as a dynamic language and testing for types in the unit tests.

But the types are already tested by the templat constraints and the fact that they compile at all. It's the functions' runtime behaviors that can't be tested, and no language can really test that at compile time, whereas unit test _do_ test the runtime behavior. So, you get both static and dynamic checks.

- Jonathan M Davis
November 09, 2012
On 2012-11-09 08:28, Jonathan M Davis wrote:

> But the types are already tested by the templat constraints and the fact that
> they compile at all. It's the functions' runtime behaviors that can't be
> tested, and no language can really test that at compile time, whereas unit
> test _do_ test the runtime behavior. So, you get both static and dynamic
> checks.

Well, I guess you're right.

-- 
/Jacob Carlborg
November 09, 2012
On Friday, 9 November 2012 at 07:29:28 UTC, Jonathan M Davis wrote:
> On Friday, November 09, 2012 08:21:38 Jacob Carlborg wrote:
>> On 2012-11-09 07:20, H. S. Teoh wrote:
>> > Well, unittests are a runtime check, and they don't *guarantee*
>> > anything. (One could, in theory, write a pathological pseudo-range that
>> > passes basic unittests but fail to behave like a range in some obscure
>> > corner case. Transient ranges would fall under that category, should we
>> > decide not to admit them as valid ranges. :-))
>> > 
>> > But of course that's just splitting hairs.
>> 
>> But since we do have a language with static typing we can at least do
>> our best to try at catch as many errors as possible at compile time. We
>> don't want to end up as a dynamic language and testing for types in the
>> unit tests.
>
> But the types are already tested by the templat constraints and the fact that
> they compile at all. It's the functions' runtime behaviors that can't be
> tested, and no language can really test that at compile time, whereas unit
> test _do_ test the runtime behavior. So, you get both static and dynamic
> checks.

I guess some runtime behavior could actually be tested at compile time using CTFE?

int doubleMe(int a) { return 2 * a }
static test = doubleMe(3);
static assert(test == 6);

But maybe that is splittin' hares as well :)

/Jonas



November 09, 2012
On Friday, 9 November 2012 at 05:11:05 UTC, Walter Bright wrote:
> Many algorithms (at least the ones in Phobos do) already do a check to ensure the inputs are the correct kind of range.

There's two annoyances there:

1) the error messages can be godawful, not giving you any indication why. It's like "Foo doesn't match any template" and you've gotta figure out just what is the problem.

2) The error is at the call site, not the declaration site. Did you just flip the order of parameters? Or is the struct itself bad?