Philippe Sigaud:

I think it's doable in D, with the usual metaprogramming suspects.

But the point is: is it a good idea?


I read this one too (similar tastes or did you read them all?).

I have read them all, of course.


I admit being a bit disappointed by the wishy-washy conclusion.

Some people work for a month to create a slides pack for a conference, and some other people work just few hours.

It was not a rigorous study, it was just a little experiment, so the "conclusions" are just hints.

More info here, but the F# code is missing:
https://github.com/psnively/types_vs_tests

An almost invisible but significant part of this talk was the Scala code that verifies the number sequences inside the type system:

https://raw.github.com/psnively/types_vs_tests/master/src/main/scala/Shapeless.scala


I use both types and unit tests (in D!),

Python has taught me the importance of unit testing, so I write tons of unittests in D too (about 2.5 lines of tests for each line of working code), and they help a lot. Unit tests, tests and contract programming are all useful to write correct D code, I use them all at the same time.

But I think idiomatic D code gives less importance to "making invalid states not representable" compared to certain functional languages like Haskell (despite D ranges are essentially type-based things).

As an example, in Haskell there is "newtype" that is the D "Typedef" done (almost) right.

Here you see an example usage of newtype:
http://rosettacode.org/wiki/Total_circles_area#Haskell:_Analytical_Solution


{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Angle = A Double
    deriving (Eq, Ord, Num, Fractional)

aPi = A pi

vAngle :: Vec -> Angle
vAngle (Vec x y) = A (atan2 y x)

aNorm :: Angle -> Angle
aNorm a | a > aPi   = a - aPi * 2
        | a < -aPi  = a + aPi * 2
        | otherwise = a


By itself "newtype Angle = A Double" is very similar to a strong typedef of Angle as a double. But then you can't do much with an Angle. To solve this problem Angle derives (using the GeneralizedNewtypeDeriving compiler extension, that has some troubles if used in some cases) the Eq, Ord, Num, Fractional type classes. This means that this Angle becomes able to support code like "a - aPi * 2" and the result is another Angle.

Maybe it's possible to do something like this in D.

Currently the Phobos Typedef is almost unusable (is someone using it?).

If you want another example look at Phobos Nullable compared to the Maybe of Haskell. Maybe is fully safe, very Handy and it's used all the time in Haskell. It's defined in the Prelude as:


data  Maybe a  =  Nothing | Just a deriving (Eq, Ord, Read, Show)

Plus some helpers and extras:

maybe              :: b -> (a -> b) -> Maybe a -> b
maybe n f Nothing  =  n
maybe n f (Just x) =  f x

instance  Functor Maybe  where
    fmap f Nothing    =  Nothing
    fmap f (Just x)   =  Just (f x)

instance  Monad Maybe  where
    (Just x) >>= k   =  k x
    Nothing  >>= k   =  Nothing
    return           =  Just
    fail s           =  Nothing



This little program that shows some important things std.typecons.Nullable isn't able to do (Maybe of Haskell doesn't share this limits/problems):


import std.stdio, std.algorithm, std.typecons;

alias Nullable!(int, -1) Position;

void foo(int[] a, Position pos) /*nothrow*/ { // allow this to be nothrow
    if (pos.isNull) {
        return;
    } else {
a[pos] = 10; // perform no nullness test here, optimization
    }
}

void bar(int[] a, Position pos) {
    a[pos] = 10; // compile-time error here?
}

void main() {
    auto data = [1, 2, 3, 4, 5];
    auto p = Position(countUntil(data, 7));
    foo(data, p);
    writeln(data);
}


Functional languages make the usage of types more handy so it's simpler to use them to make invalid states unrepresentable.

Bye,
bearophile

Reply via email to