www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Strange Loop 2012

reply "bearophile" <bearophileHUGS lycos.com> writes:
They have released the many slides packs of the "Strange Loop 
2012" conference:

https://github.com/strangeloop/strangeloop2012/tree/master/slides/sessions

(Some of those files are too much large for the normal GitHub 
interface, so to download them you need to download the zip of 
the whole conference.)

I have appreciated some of those slides packs. Two of them are:

---------------------

"Wolfe-Graph.pdf":

Programs written in functional languages are essentially written 
as many little functions (sometimes one line long in Haskell) 
that call each other. To better organize things, they have 
invented a way to define at high level such call graph, using a 
simple associative array, in Clojure language. I don't know if 
this is a good idea, but it's a simple and easy to understand 
idea, and it allows for some less simple usages, shown near the 
end of the slides pack.

---------------------

"LaucherSnively-TypesVsTests.pdf":

This pack compares strong static typing against writing 
unittests. What is the best of the two? The expected answer is 
that they are two different things, they help the programmer on 
different things, so they are both useful.

The comparison is done studing different solutions to this kata 
(a coding kata is a programming problem, it's a shape problem, 
its main purpose is not to find one solution, but to find many 
different solutions, and compare them. You are supposed to solve 
many times the same kata). They solve only the first three parts 
("stories") of this kata:

http://codingdojo.org/cgi-bin/wiki.pl?KataBankOCR

The things said in this slides pack are well know, but they are 
collected and presented nicely in a small space.

At the beginning there is a well know quotation, that is a pillar 
of functional programming (and it's widely useful in D/Rust/Scala 
code too!):

Make illegal states unrepresentable -- Yaron Minsky<

A woman has solved the kata in a mostly functional language (F#) and concluded saying: - Types save me from having to even think about certain categories of tests. - Tests help me out when I get stuck but I mostly run them in the REPL and delete. - Code is structured differently with REPL. - Most modern languages don't have a strong enough type system to make illegal states un representable. - It's easy to get lost in a space where you never deliver. - Test verify when types can't prove. Another person has used a probably less functional approach, in Scala, using more unittests, and he concludes that: - Even for such a small problem spelling out unit tests made me want to gouge out my eyeballs with a rusty spoon. - When developing property based tests every forAll made me think "could/should that be a type?". - For some use cases having examples of correct input/output gave no real guidance whatsoever. - Test code is still code with its own correctness, maintenance etc. burden. I think such notes are about equally valid for functional and OOP languages. Bye, bearophile
Oct 15 2012
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Tue, Oct 16, 2012 at 1:39 AM, bearophile <bearophileHUGS lycos.com> wrote:
 "Wolfe-Graph.pdf":

I read this one on the plane today. Clojure does make for some elegant code. I think it's doable in D, with the usual metaprogramming suspects.
 "LaucherSnively-TypesVsTests.pdf":

 This pack compares strong static typing against writing unittests. What is
 the best of the two? The expected answer is that they are two different
 things, they help the programmer on different things, so they are both
 useful.

I read this one too (similar tastes or did you read them all?). I admit being a bit disappointed by the wishy-washy conclusion. I use both types and unit tests (in D!), but I'm more a static typing guy myself.
Oct 16 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
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
Oct 16 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
 https://raw.github.com/psnively/types_vs_tests/master/src/main/scala/Shapeless.scala

If this is equivalent, then in D it was too much easy: import std.typetuple: allSatisfy, staticIndexOf; struct Digit(size_t N) { enum uint n = N; } // No "static foreach", so: alias Digit!0 _0; alias Digit!1 _1; alias Digit!2 _2; alias Digit!3 _3; alias Digit!4 _4; alias Digit!5 _5; alias Digit!6 _6; alias Digit!7 _7; alias Digit!8 _8; alias Digit!9 _9; template isDigit(alias T) { enum isDigit = staticIndexOf!(T, _0,_1,_2,_3,_4,_5,_6,_7,_8,_9) != -1; } bool isValid(Digits...)() { static if (Digits.length != 9 || !allSatisfy!(isDigit, Digits)) return false; else { uint total = 0; /*static*/ foreach (i, Dig; Digits) total += (9 - i) * Dig.n; return total % 11 == 0; } } void main() { static assert(!isValid!(_0, _1)()); static assert( isValid!(_3, _4, _5, _8, _8, _2, _8, _6, _5)()); static assert( isValid!(_1, _2, _3, _4, _5, _6, _7, _8, _9)()); static assert(!isValid!(_3, _1, _5, _8, _8, _2, _8, _6, _5)()); static assert(!isValid!(_3, _4, _5, _8, _8, _2, _8, _6)()); } Bye, bearophile
Oct 16 2012
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Wed, Oct 17, 2012 at 4:54 AM, bearophile <bearophileHUGS lycos.com> wrote:
 https://raw.github.com/psnively/types_vs_tests/master/src/main/scala/Shapeless.scala

If this is equivalent, then in D it was too much easy:

Why not use integral template parameters directly? And checking if all params are between 0 and 9, of course. The user syntax would then be cleaner: void main() { static assert(!isValid!(0, 1)()); static assert( isValid!(3, 4, 5, 8, 8, 2, 8, 6, 5)()); static assert( isValid!(1, 2, 3, 4, 5, 6, 7, 8, 9)()); } And, of course, there is no need for templates at all. A standard, compile-time interpreted function could do it for you: void main() { static assert(!isValid(0, 1)); static assert( isValid(3, 4, 5, 8, 8, 2, 8, 6, 5)); static assert( isValid(1, 2, 3, 4, 5, 6, 7, 8, 9)); }
Oct 17 2012