January 18, 2014
On 1/18/2014 3:10 PM, bearophile wrote:
> Walter Bright:
>
>>> Currently you can't implement
>>> "good enough" not-nullable reference types or ranged integers in D).
>>
>> This is not at all clear.
>
> A good Ranged should allow syntax like this, and it should catch this error at
> compile time (with an "enum precondition"):
>
> Ranged!(int, 0, 10)[] arr = [1, 5, 12, 3, 2];
>
> It also should use the CPU overflow/carry flags to detect efficiently enough
> integer overflows on a Ranged!(uint, 0, uint.max) type. It should handle the
> conversions nicely to the super-type and allow the usage of a ranged int as
> array index. And array bound tests should be disabled if you are using a ranged
> size_t that is statically known to be in the interval of the array, because this
> is one of the main purposes of ranged integrals.
>
> And D arrays should have optional strongly-typed index types, as in Ada. Because
> this makes the code safer, easier to reason about, and even faster (thanks to
> disabling some now unnecessary array bound tests).

While these are all desirable features, it is not clear that these cannot be implemented without changing the language - for example, improved optimization can do a lot.

And secondly, you said "good enough" not "perfect". Even putting things into the language does not imply they will be perfect, as experience amply shows.


> Similarly not-nullable pointers and class references have some semantic
> requirements that are not easy to implement in D today.

For example?

January 18, 2014
On Saturday, 18 January 2014 at 21:05:02 UTC, Walter Bright wrote:
> On 1/17/2014 7:05 AM, Michel Fortin wrote:
>> Some more thoughts.
>
> The postfix ? has parsing issues with ?: expressions.
>
> Aside from that, non-null is only one case of a universe of types that are subsets of other types. I'd prefer a more general solution.

I was thinking about defining reference types (classes, interfaces) as considered non nullable in @safe . It is still possible to encapsulate null in NonNull!T .
January 18, 2014
On Saturday, 18 January 2014 at 21:05:02 UTC, Walter Bright wrote:
> On 1/17/2014 7:05 AM, Michel Fortin wrote:
>> Some more thoughts.
>
> The postfix ? has parsing issues with ?: expressions.
>
> Aside from that, non-null is only one case of a universe of types that are subsets of other types. I'd prefer a more general solution.

I was thinking about defining reference types (classes,
interfaces) as considered non nullable in @safe . It is still
possible to encapsulate null in Nullable!T .
January 18, 2014
I somehow missed this post, so a delayed response.

On Saturday, 18 January 2014 at 01:22:48 UTC, Walter Bright wrote:
> First off, in all these scenarios you describe, how does not having a null make it EASIER to track down the bug?

I have not argued for not having a null. I have argued for trapping null, instantiating a type specific default and recover if the type's meta says so. That default could be to issue a NullException. At that point you should be able to log null dereferences too.

I have previously argued that non-null pointers is nice, but only if you have whole program analysis. Otherwise you'll end up injecting null-tests everywhere.

> there's a bug in the code. It's quite another to have a critical system start behaving erratically because of a bug.

Yes, and this is a problematic definition since "erratic" is kind of subjective given that most systems don't follow the model 100%.

> do. The correct way is when the bug is detected, that software is IMMEDIATELY SHUT DOWN and the backup is engaged. If you don't have such a backup, you have a very, very badly designed system.

In that case 99.99% of all software is very, very badly designed.

DMD inclusive.

Human beings too, but we happen to be fault tolerant, not by using backups, but by being good at recovery and dealing in a fuzzy way with incomplete or wrong information.
January 19, 2014
On 2014-01-18 22:28:14 +0000, Walter Bright <newshound2@digitalmars.com> said:

> On 1/18/2014 2:16 PM, Michel Fortin wrote:
>> It works, up to a point.
>> 
>>      void foo(RangedInt!(0, 5) a);
>> 
>>      void bar(RangedInt!(0, 10) a)
>>      {
>>          if (a < 5)
>>              foo(a); // what happens here?
>>      }
>> 
>> In that "foo(a)" line, depending on the implementation of RangedInt you either
>> get a compile-time error that RangedInt!(0, 10) can't be implicitly converted to
>> RangedInt!(0, 5) and have to explicitly convert it, or you get implicit
>> conversion with a runtime check that throws.
> 
> Yes, and I'm not seeing the problem. (The runtime check may also be removed by the optimizer.)

I'm not concerned about performance, but about catching bugs early. You said it: the compiler (the optimizer) knows (more or less) whether it is possible for you to have an error here (which is why the check might disappear as dead code), but it will let it pass and make the generated code wait until a bad value is passed at runtime to throw something.

Couldn't we tell the compiler to emit an error if a function argument "might" be in the offending range instead? That'd be much more useful to find bugs, because you'd find them at compile-time.


>> Just like pointers, not knowing about the actual control flow pushes range
>> constrains enforcement at runtime in situations like this one.
> 
> With pointers, the enforcement only happens when converting a pointer to a nonnull pointer.

True.


>> In fact, even the most obvious case can't be caught at compile-time with the
>> template approach:
>> 
>>      void baz()
>>      {
>>          foo(999); // runtime error here
>>      }
> 
> Sure it can. Inlining, etc., and appropriate use of compile time constraints.

Inlining will not allow the error to be caught at compile time, although it might allow the runtime check to be eliminated as dead code. But this is not about performance, it's about detecting this kind of bug early (at compile time).


-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca

January 19, 2014
On 1/18/2014 3:34 PM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang@gmail.com>" wrote:
>> do. The correct way is when the bug is detected, that software is IMMEDIATELY
>> SHUT DOWN and the backup is engaged. If you don't have such a backup, you have
>> a very, very badly designed system.
>
> In that case 99.99% of all software is very, very badly designed.
>
> DMD inclusive.

You elided the qualification "If it is a critical system". dmd is not a safety critical application.

January 19, 2014
On Sunday, 19 January 2014 at 02:33:15 UTC, Walter Bright wrote:
> You elided the qualification "If it is a critical system". dmd is not a safety critical application.

Nor are 99.99%, possibly 100%, of the applications currently being built with D. The points are valid, no safety critical application should ever rely on any individual components not failing. But for the purpose of D, they are not particularly applicable. People are just arguing over two different things (safety critical code vs standard D code), with neither disagreeing with the others, simply bringing up different situations.
January 19, 2014
On 1/18/2014 11:11 PM, Kapps wrote:
> On Sunday, 19 January 2014 at 02:33:15 UTC, Walter Bright wrote:
>> You elided the qualification "If it is a critical system". dmd is not a safety
>> critical application.
>
> Nor are 99.99%, possibly 100%, of the applications currently being built with D.

Sociomantic uses D to write trading software. I think they'd be ill advised to write code in such a way that it continues making trades after entering an invalid state, as in it could be very expensive.

Furthermore, part of the reason why I am adamant about this is far too often I run into, including in this thread, programmers who believe that the way to write critical software is to keep the program running even if it has failed.


> The points are valid, no safety critical application should ever rely on any
> individual components not failing. But for the purpose of D, they are not
> particularly applicable.

I don't buy that this is not applicable for D. D must not promote unsafe (as in potentially life threatening) programming practice as a "best practice". You never know how somebody is going to use a programming language.


> People are just arguing over two different things
> (safety critical code vs standard D code), with neither disagreeing with the
> others, simply bringing up different situations.

There has been a lot of misunderstandings and miscommunications in this thread. I do my best to clear them up.

January 19, 2014
On 1/18/2014 6:33 PM, Walter Bright wrote:
> You elided the qualification "If it is a critical system". dmd is not a safety
> critical application.


And I still practice what I preach with DMD. DMD never attempts to continue running after it detects that it has entered an invalid state - it ceases immediately. Furthermore, when it detects any error in the source code being compiled, it does not generate an object file.

January 19, 2014
On 01/18/2014 10:05 PM, Walter Bright wrote:
> On 1/17/2014 7:05 AM, Michel Fortin wrote:
>> Some more thoughts.
>
> The postfix ? has parsing issues with ?: expressions.
> ...

In what sense? It can be unambiguously parsed easily.

> Aside from that, non-null is only one case of a universe of types that
> are subsets of other types.

This is not true. The main rationale for "non-null" is to eliminate null dereferences. A? in his proposal is different from current nullable references in that the compiler does not allow them to be dereferenced.

If we just had a solution for arbitrary subset types, we'd _still_ be left with a type of references that might be null, but are not prevented to be dereferenced.


Besides, I think it is strange to think of valid references as just being some arbitrary special case of nullable references. A nullable reference is roughly what you get when you put an arbitrary incompatible value 'null' into the set of valid references:

{valid references} ∪ {null}

All that is asked for is to make the disjunct that is _actually interesting_ it's own type. Sure, it could be described as:

{x ∈ ({valid references} ∪ {null}) | x ≠ null}

But I think this is a silly way of expressing oneself.

> I'd prefer a more general solution.
>

Subset types are not more general than the proposed feature.