Constrained genericity: Difference between revisions

Line 1,166:
{{out}}
<lang>Yummy.new(foodbox => {})</lang>
 
=={{header|Phix}}==
No interfaces per se, but you can explicitly test manually for these sort of things.
Needs 0.8.1+
=== using generic types ===
<lang Phix>include builtins\structs.e as structs
 
class foodbox
sequence contents = {}
procedure add(class food)
-- (aside: class food is 100% abstract here...
-- ie: class is *the* root|anything class,
-- and food is just an arbitrary name)
integer t = structs:get_field_flags(food,"eat")
if t!=SF_PROC+SF_PUBLIC then
throw("not edible") -- no public method eat...
end if
-- you might also want something like this:
-- t = structs:fetch_field(food,"eat")
-- if t=NULL then
-- throw("eat not implemented")
-- end if
this.contents = append(this.contents,food)
end procedure
procedure dine()
integer l = length(this.contents)
string s = iff(l=1?"":"s")
printf(1,"foodbox contains %d item%s\n",{l,s})
for i=1 to l do
class food = this.contents[i];
--food.eat(); -- error...
-- If you don't define an [abstract] eat() method, or use
-- "class", you end up having to do something like this:
integer eat = structs:fetch_field(food,"eat")
eat(food)
end for
end procedure
end class
foodbox lunchbox = new()
 
class fruit
string name
procedure eat()
printf(1,"mmm... %s\n",{this.name})
end procedure
end class
fruit banana = new({"banana"})
 
class clay
string name = "fletton"
end class
clay brick = new()
 
lunchbox.add(banana)
try
lunchbox.add(brick) -- throws exception
catch e
printf(1,"%s line %d error: %s\n",{e[E_FILE],e[E_LINE],e[E_USER]})
end try
lunchbox.dine()</lang>
{{out}}
<pre>
test.exw line 9 error: not edible
foodbox contains 1 item
mmm... banana
</pre>
=== using abstract types ===
With added milkshake, note that <i>our</i> foodbox <i>can</i> contain <i>both</i> fruit <i>and</i> drink<i>!</i><br>
- we would not even need to change the foodbox to be allowed to put sandwiches and biscuits in it either!<br>
Of course you could trivially create a fruit-only foodbox just by changing the one line(ie 8) to add(fruit food).<br>
What is much harder(/left as an exercise) is to dynamically change those kinds of restrictions at run-time.
<lang Phix>abstract class edible
string name
procedure eat(); -- (virtual)
end class
 
class foodbox2
sequence contents = {}
procedure add(edible food)
if food.eat=NULL then -- (optional)
throw("eat() not implemented")
end if
this.contents = append(this.contents,food)
end procedure
procedure dine()
integer l = length(this.contents)
string s = iff(l=1?"":"s")
printf(1,"foodbox2 contains %d item%s\n",{l,s})
for i=1 to l do
-- this.contents[i].eat() -- not supported, sorry!
-- compiler needs some more type hints, such as:
edible food = this.contents[i]
food.eat()
end for
end procedure
end class
foodbox2 lunchbox2 = new()
 
class fruit2 extends edible
procedure eat()
printf(1,"mmm... %s\n",{this.name})
end procedure
end class
fruit2 banana2 = new({"banana"})
 
class clay2
string name = "common fletton"
end class
clay2 brick2 = new()
 
class drink extends edible
procedure eat()
printf(1,"slurp... %s\n",{this.name})
end procedure
end class
drink milkshake = new({"milkshake"})
 
lunchbox2.add(banana2)
try
lunchbox2.add(brick2) -- triggers typecheck
catch e
printf(1,"%s line %d: %s\n",{e[E_FILE],e[E_LINE],e[E_USER]})
end try
lunchbox2.add(milkshake)
lunchbox2.dine()</lang>
{{out}}
<pre>
test.exw line 8: type check failure, food is {"struct","clay2",8,1}
foodbox2 contains 2 items
mmm... banana
slurp... milkshake
</pre>
 
=={{header|PicoLisp}}==
7,806

edits