Strange Loop 2012

bearophile bearophileHUGS at lycos.com
Tue Oct 16 14:34:21 PDT 2012


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


More information about the Digitalmars-d mailing list