On 6 July 2011 16:37, Mark Proctor <mproctor@codehaus.org> wrote:
http://blog.athico.com/2011/07/traits-duck-typing-and-dynamic-semantic.html
-----
Duck typing is the ability to say that something implements an
interface. In this article I'll focus on triples (sets of key value
pairs) such as Maps in Java or Dictionaries in other languages.
The terms map and triple set will be used interchangeably.
I'll use MVEL like syntax to demonstrate:
bean = [ name = "Zod", age = 150 ]
bean dons Human
assertEquals( "Zod", bean.name )
assertEquals( 150, bean.age)
Without the don's keyword to duck type the map to the interface this
would not compile as the compiler
would report a static typing error of
unknown fields for “name” and “age”.
rule Human when
$tp : Map( this contains [ "name" : String, "age" : int ] )
then
$tp dons Human// that $tp instance is now recognised by all other rules that match on Human
end
rule HelloWorld when
$s : Human() // this will actually match against the Map "donned" to Human
then
println( "hello " + $s.name );
end
We can see the rule that applies the trait can probably have a first
class representation for it's use case.
For instance if someone is Human and is also 18 years of age or younger
we can apply a further abstraction and say the are not just Human but
also a Student. We use the "dons" keyword after the arguments to say the
existing traits the Map must already wear, i.e. abstractions we already
know about the thing.
trait Student( String name, int age ) dons Human when
age(< 18; )
end
"name" and "age" both have to be represented as objects the system is
going to bloat fast.
The relations are what we refer to for
each of the key/value pairs in the triple set, i.e. a property (bean
getter and setter pair, normally on a member field) is a relation on a
class.
which is generated as an actual class from which beans can be initiated,
“name”, “age” and “gender” are static relations. Young, Boy and
FussyEater are all interfaces.
Human extends TripleSet so that we know
that further dynamic relations can be added and traits applied. We
detect the bean instance is “< 18” and thus the trait Young is applied
and that if the gender is M the trait Boy is applied. Further if a
property exists, either static or dynamic (the two are seamless in the
syntax) called “dislikes” with a value of “carrots” we apply the
FussyEater trait.
declare Human extends TripleSet
String name;
int age;
Gender gender; // M/F enum
end<
trait Young(int age) dons Human when
age(< 18; )
en
trait Boy(Gender gender) dons Young when
Gender( Gender.M; )
end
trait FussyEater(String dislikes) dons Boy when
dislikes( “carrots”; )
end
Human human = new Human( “Zod”, 16 )
human.add( [dislikes : “carrots”] )
insert ( human )
insert( new GiveIceCream( human ) );
We can now have a single rule that disallows fussy eaters from getting
ice cream. How cool is that :)
rule “Don't give icecream to boys who are fussy eaters”
$f : FussyEater()
$d : GiveIceCream( $f; )
then
retract ( $d )
end