April 04, 2014
On Friday, 4 April 2014 at 01:31:20 UTC, bearophile wrote:
> The point of that part of the rant is that using an integer is very not-precise, typing-wise. Having more precise typing sometimes helps.
>
> In a little higher level language using a 3-value enum (as in Haskell, more or less) is still sufficiently efficient. And Ada language shows that often you can have both precise types (strong typing) and almost C-like efficiency.
>
> Bye,
> bearophile

I would agree if D actually had type-safe enums.

enum a
{
    val = 1
}
	
enum b
{
    val = 1
}

assert(a.val - b.val == 0);
April 04, 2014
On Fri, Apr 04, 2014 at 00:59:23 +0000, Meta wrote:
> His examination of the compare function was interesting. I think, though, that it's misguided, and not one of Scala's problems.

Maybe not major, but it's not completely ignorable.

> Returning an int to denote less than, equal, and greater than is a very small complexity, and makes it very fast to check the result.

See, this is *exactly* his point. You're basically putting the "well, C does it" and "int is fast" as your rationale. I think by this point, we (as a collective community) have seen that C has some serious flaws when you start allowing user input from untrusted sources into your code. The latter is easily classified as premature optimization.

There is *zero* rationale as to why this would be a compilable implementation of comparison:

    int compare(int a, int b) {
        return a * b;
    }

The fact that this compiles when used as a comparison is *insane* when you take a fresh look at how you can construct a language.

If you have sum types, you can both deny the above silliness and represent it as an integer and be just fine. In fact, you're possibly better off since you can now do:

    add $offset $compare_result
    jmp *$offset

rather than doing 2 comparisons and a branch since you *know* the result will never be more than 2.

--Ben
April 04, 2014
On Friday, 4 April 2014 at 01:51:58 UTC, Walter Bright wrote:
> Since in D you can detect if a function is pure, and specialize accordingly, it is not necessary to require that the filter function be pure.

That's true, but then somebody somewhere accidentally passes in a delegate that references some outside state, and performance is suddenly shot for no apparent reason. The upside in D is that you can explicitly mark delegates as pure and have the compiler check for you, but that still puts the onus on the user to be disciplined and not forget.
April 04, 2014
On Thu, Apr 03, 2014 at 18:51:56 -0700, Walter Bright wrote:
> Since in D you can detect if a function is pure, and specialize accordingly, it is not necessary to require that the filter function be pure.

Is there a built-in compose operator or function (Haskell's (.)
operator)? How would you copy the common attributes of the composed
functions to the new function (if not builtin)?

--Ben
April 04, 2014
Meta:

> I would agree if D actually had type-safe enums.
>
> enum a
> {
>     val = 1
> }
> 	
> enum b
> {
>     val = 1
> }
>
> assert(a.val - b.val == 0);

C enums are mostly type unsafe. C++11 has enum class that is strongly typed. D enums are intermediate (and it has final switches). I have asked for fully typesafe enums in D, but in several years I think Walter has never answered, nor he has explained why D has chosen such intermediate point. I presume this choice is based on practical reasons, but I don't know exactly what they are (perhaps to minimize the number of casts). D used to have several corners of weak typing (like a partial confusion between pointers and dynamic arrays) that later have being (painfully and slowly) fixed (and this despite D Zen is supposed to prefer a strict design first, followed by some relaxations later).

Bye,
bearophile
April 04, 2014
On 4/3/2014 7:01 PM, Ben Boeckel wrote:
> Is there a built-in compose operator or function (Haskell's (.)
> operator)? How would you copy the common attributes of the composed
> functions to the new function (if not builtin)?


The compiler does attribute inference for template functions and lambdas.
April 04, 2014
On 4/3/2014 7:00 PM, Meta wrote:
> The upside in D is that you can explicitly mark delegates as pure and
> have the compiler check for you, but that still puts the onus on the user to be
> disciplined and not forget.

It's really like everything else in programming - at some point, if you don't avail yourself of the checking features, you have to check it yourself.
April 04, 2014
On 4/3/2014 7:19 PM, bearophile wrote:
> I have asked for fully
> typesafe enums in D, but in several years I think Walter has never answered, nor
> he has explained why D has chosen such intermediate point. I presume this choice
> is based on practical reasons, but I don't know exactly what they are (perhaps
> to minimize the number of casts).

Because every cast breaks the type system. A type system that requires too many casts for normal things is NOT a type safe system.

I have explained this on numerous occasions.

April 04, 2014
On 4/3/2014 7:19 PM, bearophile wrote:
> I have asked for fully typesafe enums in D,

You can do this:

   struct MyInt {
       int x;
       alias this x;
       ... put your various constraints here ...
   }

to get typesafe enums. In fact, you can use this construct to create a type that overrides selected behaviors of any other type.
April 04, 2014
On Friday, 4 April 2014 at 04:31:41 UTC, Walter Bright wrote:
> On 4/3/2014 7:19 PM, bearophile wrote:
>> I have asked for fully typesafe enums in D,
>
> You can do this:
>
>    struct MyInt {
>        int x;
>        alias this x;
>        ... put your various constraints here ...
>    }
>
> to get typesafe enums. In fact, you can use this construct to create a type that overrides selected behaviors of any other type.

Combined with your other post about casts, I'm not sure we're talking about the same kind of type-safety. In the case of your example, alias this does not make it typesafe, as a MyInt can still be implicitly converted to int.

struct MyInt
{
	int x;
	alias x this;
}

void takesInt(int n)
{
}

void main()
{
        //Fine
	takesInt(MyInt(1));	
}


Implicit conversions are generally not a facet of type-safe systems. Saying that too-strong typing is bad because casts break the type system is a strawman, although I agree that there is a balance that must be struck.