Duck typing en F#

Un exemple pour obtenir du duck typing (typage dynamique) en F#.

Certaines personnes (développeurs Ruby, Python...) aiment le duck typing. Pour ma part, je préfère le typage statique, fort et inféré, même si le typage dynamique a parfois ses avantages. En F#, il est possible d'obtenir du duck typing: il suffit d'utiliser l'introspection. Voici une petite classe pour d'exemple :

[fsharp]
open System.Reflection
 
type Duck(value: obj) =
    let mutable value = value
    let mutable ty = value.GetType()
    member d.Type = ty
    member d.Cast<'a>() = unbox<'a> value
 
    member d.Exec(str, args) = 
        Duck (ty.InvokeMember(str, BindingFlags.GetProperty ||| BindingFlags.InvokeMethod, null, value, args))
 
    member d.X(str) =
        d.Exec(str, [||])
 
    member d.X(str, arg1) =
        d.Exec(str, [|box arg1|])
 
    member d.X(str, arg1, arg2) =
        d.Exec(str, [|box arg1; box arg2|])
 
    member d.Item with get str = d.Exec(str, [||])
    member d.Val with get() = value
                 and  set (x:obj) = value <- x; ty <- value.GetType()

Et voici un exemple d'utilisation :

[fsharp]
let a = Duck 42
 
a.Val <- "test"          // modifie a: il contient maintenant une chaine
a.["Length"]             // renvoie 4
a.X("Contains", "st")    // exécute une méthode - renvoie true
 
let b = Duck [1; 2; 3]
b.Val <- b.["Length"]
 
b.Type.ToString()        // renvoie "System.Int32"
printfn "%d" (b.Cast())  // affiche 3

La méthode Cast est utilisée pour obtenir une valeur typée. b.Cast<int>() essaie de renvoyer un int (la conversion est testée à l'exécution). L'annotation de type n'est pas toujours nécessaire, du fait de l'inférence de type.

[fsharp]
> let length d : int = (Duck d).["Length"].Cast();;
 
val length : 'a -> int
 
> length "test";;
val it : int = 4
> length [1; 2];;
val it : int = 2

Bien sûr, tout ce code n'est pas sûr : les noms des méthodes peuvent être calculés à l'exécution, peuvent provenir d'entrées utilisateur ou encore contenir des fautes de frappe. Dès que l'on appelle la méthode Cast, on revient dans le monde sûr et statiquement vérifié de F#.

Comments

1. On Tuesday, June 2 2009, 11:31 by jcm

Bonjour,

Le duck typing controllé statiquement existe en F#.
Voir www.atrevido.net/blog/200...

J-C

2. On Tuesday, June 2 2009, 18:22 by Laurent

Bonjour,

C'est en effet le mécanisme utilisé dans la bibliothèque standard. Mais cela vient avec une syntaxe très lourde et plusieurs limitations. Cette pratique est déconseillée par l'équipe F# (ce n'est pas prévu pour être utilisé en dehors de la bibliothèque standard).

C'est toutefois une fonctionnalité intéressante et j'ai demandé plusieurs fois à avoir du sucre syntaxique pour faire la même chose.