Constrained genericity: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Ruby}}: Added Ruby)
m (→‎{{header|Wren}}: Changed to Wren S/H)
(26 intermediate revisions by 17 users not shown)
Line 19: Line 19:
Ada allows various constraints to be specified in parameters of generics.
Ada allows various constraints to be specified in parameters of generics.
A formal type constrained to be derived from certain base is one of them:
A formal type constrained to be derived from certain base is one of them:
<lang ada>with Ada.Containers.Indefinite_Vectors;
<syntaxhighlight lang="ada">with Ada.Containers.Indefinite_Vectors;


package Nutrition is
package Nutrition is
Line 42: Line 42:
subtype Food_Box is Food_Vectors.Vector;
subtype Food_Box is Food_Vectors.Vector;


end Food_Boxes;</lang>
end Food_Boxes;</syntaxhighlight>
The package Nutrition defines an interface of an eatable object, that is, the procedure Eat. Then a generic container package is defined with the elements to be of some type derived from Food. Example of use:
The package Nutrition defines an interface of an eatable object, that is, the procedure Eat. Then a generic container package is defined with the elements to be of some type derived from Food. Example of use:
<lang ada>type Banana is new Food with null record;
<syntaxhighlight lang="ada">type Banana is new Food with null record;
overriding procedure Eat (Object : in out Banana) is null;
overriding procedure Eat (Object : in out Banana) is null;
package Banana_Box is new Food_Boxes (Banana);
package Banana_Box is new Food_Boxes (Banana);
Line 51: Line 51:
overriding procedure Eat (Object : in out Tomato) is null;
overriding procedure Eat (Object : in out Tomato) is null;
package Tomato_Box is new Food_Boxes (Tomato);
package Tomato_Box is new Food_Boxes (Tomato);
-- We have declared Banana and Tomato as a Food.</lang>
-- We have declared Banana and Tomato as a Food.</syntaxhighlight>
The Tomato_Box can only contain tomatoes; the Banana_Box can only contain bananas. You can only create boxes of eatable objects.
The Tomato_Box can only contain tomatoes; the Banana_Box can only contain bananas. You can only create boxes of eatable objects.

=={{header|C sharp|C#}}==
In C#, type constraints are made on the type hierarchy, so here we make <code>IEatable</code> an interface, with an <code>Eat</code> method.
Types which are eatable would have to implement the
<code>IEatable</code> interface and provide an <code>Eat</code> method.
<syntaxhighlight lang="csharp">interface IEatable
{
void Eat();
}</syntaxhighlight>
Type constraints in type parameters can be made via the <code>where</code> keyword, which allows us to qualify T.
In this case, we indicate that the type argument must be a type
that is a subtype of <code>IEatable</code>.
<syntaxhighlight lang="csharp">using System.Collections.Generic;

class FoodBox<T> where T : IEatable
{
List<T> food;
}</syntaxhighlight>
For example, an eatable Apple:
<syntaxhighlight lang="csharp">class Apple : IEatable
{
public void Eat()
{
System.Console.WriteLine("Apple has been eaten");
}
}</syntaxhighlight>
C# also has the interesting functionality of being able to require that a generic type have a default constructor. This means that the generic type can actually instantiate the objects without ever knowing the concrete type. To do so, we constrain the where clause with an additional term "new()". This must come after any other constraints. In this example, any type with a default constructor that implements IEatable is allowed.
<syntaxhighlight lang="csharp">using System.Collections.Generic

class FoodMakingBox<T> where T : IEatable, new()
{
List<T> food;

void Make(int numberOfFood)
{
this.food = new List<T>();
for (int i = 0; i < numberOfFood; i++)
{
this.food.Add(new T());
}
}
}</syntaxhighlight>


=={{header|C++}}==
=={{header|C++}}==
{{works with|C++11}}
{{works with|C++11}}
Uses static assertion to disallow instantiations on incorrect types
Uses static assertion to disallow instantiations on incorrect types
<syntaxhighlight lang="cpp">template<typename T> //Detection helper struct
<lang c++>
template<typename T> //Detection helper struct
struct can_eat //Detects presence of non-const member function void eat()
struct can_eat //Detects presence of non-const member function void eat()
{
{
Line 90: Line 131:
//Following leads to compile-time error
//Following leads to compile-time error
//FoodBox<brick> practical_joke;
//FoodBox<brick> practical_joke;
}</lang>
}</syntaxhighlight>

=={{header|C sharp|C#}}==
In C#, type constraints are made on the type hierarchy, so here we make <code>IEatable</code> an interface, with an <code>Eat</code> method.
Types which are eatable would have to implement the
<code>IEatable</code> interface and provide an <code>Eat</code> method.
<lang csharp>interface IEatable
{
void Eat();
}</lang>
Type constraints in type parameters can be made via the <code>where</code> keyword, which allows us to qualify T.
In this case, we indicate that the type argument must be a type
that is a subtype of <code>IEatable</code>.
<lang csharp>using System.Collections.Generic;

class FoodBox<T> where T : IEatable
{
List<T> food;
}</lang>
For example, an eatable Apple:
<lang csharp>class Apple : IEatable
{
public void Eat()
{
System.Console.WriteLine("Apple has been eaten");
}
}</lang>
C# also has the interesting functionality of being able to require that a generic type have a default constructor. This means that the generic type can actually instantiate the objects without ever knowing the concrete type. To do so, we constrain the where clause with an additional term "new()". This must come after any other constraints. In this example, any type with a default constructor that implements IEatable is allowed.
<lang csharp>using System.Collections.Generic

class FoodMakingBox<T> where T : IEatable, new()
{
List<T> food;

void Make(int numberOfFood)
{
this.food = new List<T>();
for (int i = 0; i < numberOfFood; i++)
{
this.food.Add(new T());
}
}
}</lang>


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
Line 156: Line 155:


The only shortcoming here is that the compiler isn't required to enforce the type specifications for the arrays. A custom insert function, however, could remember the specified type for the collection, and assert that inserted elements are of that type.
The only shortcoming here is that the compiler isn't required to enforce the type specifications for the arrays. A custom insert function, however, could remember the specified type for the collection, and assert that inserted elements are of that type.
<lang lisp>(defclass food () ())
<syntaxhighlight lang="lisp">(defclass food () ())


(defclass inedible-food (food) ())
(defclass inedible-food (food) ())
Line 189: Line 188:
"Return an array whose elements are declared to be of type (and
"Return an array whose elements are declared to be of type (and
eatable food)."
eatable food)."
(apply 'make-food-box 'eatable array-args))</lang>
(apply 'make-food-box 'eatable array-args))</syntaxhighlight>

=={{header|Crystal}}==
Similar to Ruby version, but shows error at compile-time.
<syntaxhighlight lang="ruby">class Apple
def eat
end
end

class Carrot
def eat
end
end

class FoodBox(T)
def initialize(@data : Array(T))
{% if T.union? %}
{% raise "All items should be eatable" unless T.union_types.all? &.has_method?(:eat) %}
{% else %}
{% raise "Items should be eatable" unless T.has_method?(:eat) %}
{% end %}
end
end

FoodBox.new([Apple.new, Apple.new])
FoodBox.new([Apple.new, Carrot.new])
FoodBox.new([Apple.new, Carrot.new, 123])</syntaxhighlight>

{{out}}
<pre>
Error in line 23: All items should be eatable
</pre>


=={{header|D}}==
=={{header|D}}==
===Template Version===
===Template Version===
<lang d>enum IsEdible(T) = is(typeof(T.eat));
<syntaxhighlight lang="d">enum IsEdible(T) = is(typeof(T.eat));


struct FoodBox(T) if (IsEdible!T) {
struct FoodBox(T) if (IsEdible!T) {
Line 211: Line 241:


//FoodBox!Car carsBox; // Not allowed
//FoodBox!Car carsBox; // Not allowed
}</lang>
}</syntaxhighlight>


===Interface Version===
===Interface Version===
<lang d>interface IEdible { void eat(); }
<syntaxhighlight lang="d">interface IEdible { void eat(); }


struct FoodBox(T : IEdible) {
struct FoodBox(T : IEdible) {
Line 230: Line 260:
FoodBox!Carrot carrotBox; // OK
FoodBox!Carrot carrotBox; // OK
//FoodBox!Car carBox; // Not allowed
//FoodBox!Car carBox; // Not allowed
}</lang>
}</syntaxhighlight>


=={{header|E}}==
=={{header|E}}==
It is surely arguable whether this constitutes an implementation
It is surely arguable whether this constitutes an implementation
of the above task:
of the above task:
<lang e>/** Guard accepting only objects with an 'eat' method */
<syntaxhighlight lang="e">/** Guard accepting only objects with an 'eat' method */
def Eatable {
def Eatable {
to coerce(specimen, ejector) {
to coerce(specimen, ejector) {
Line 248: Line 278:
def makeFoodBox() {
def makeFoodBox() {
return [].diverge(Eatable) # A guard-constrained list
return [].diverge(Eatable) # A guard-constrained list
}</lang>
}</syntaxhighlight>


=={{header|Eiffel}}==
=={{header|Eiffel}}==
Line 256: Line 286:
The "eatable" characteristic is modeled by a deferred class (deferred classes are similar to abstract classes in some other languages).
The "eatable" characteristic is modeled by a deferred class (deferred classes are similar to abstract classes in some other languages).


<lang eiffel >
<syntaxhighlight lang="eiffel ">
deferred class
deferred class
EATABLE
EATABLE
Line 267: Line 297:
end
end
end
end
</syntaxhighlight>
</lang>


Class <code lang="eiffel">EATABLE</code> can then be inherited by any other class, with the understanding that the inheriting class will have to provide an implementation for the procedure <code lang="eiffel">eat</code>. Here are two such classes, <code lang="eiffel">APPLE</code> and <code lang="eiffel">PEAR</code>:
Class <code lang="eiffel">EATABLE</code> can then be inherited by any other class, with the understanding that the inheriting class will have to provide an implementation for the procedure <code lang="eiffel">eat</code>. Here are two such classes, <code lang="eiffel">APPLE</code> and <code lang="eiffel">PEAR</code>:


<lang eiffel >
<syntaxhighlight lang="eiffel ">
class
class
APPLE
APPLE
Line 286: Line 316:
end
end
end
end
</syntaxhighlight>
</lang>




<lang eiffel >
<syntaxhighlight lang="eiffel ">
class
class
PEAR
PEAR
Line 304: Line 334:
end
end
end
end
</syntaxhighlight>
</lang>


Instances of the generic class <code lang="eiffel">FOOD_BOX</code> can contain any types of <code lang="eiffel">EATABLE</code> items. The constraint is shown in the formal generics part of the class declaration for <code lang="eiffel">FOOD_BOX</code>:
Instances of the generic class <code lang="eiffel">FOOD_BOX</code> can contain any types of <code lang="eiffel">EATABLE</code> items. The constraint is shown in the formal generics part of the class declaration for <code lang="eiffel">FOOD_BOX</code>:


<lang eiffel>
<syntaxhighlight lang="eiffel">
class
class
FOOD_BOX [G -> EATABLE]
FOOD_BOX [G -> EATABLE]
Line 319: Line 349:


end
end
</syntaxhighlight>
</lang>


So, any declaration of type <code lang="eiffel">FOOD_BOX</code> can constrain its contents to any particular eatable type. For example:
So, any declaration of type <code lang="eiffel">FOOD_BOX</code> can constrain its contents to any particular eatable type. For example:


<lang eiffel>
<syntaxhighlight lang="eiffel">
my_apple_box: FOOD_BOX [APPLE]
my_apple_box: FOOD_BOX [APPLE]
</syntaxhighlight>
</lang>


The entity <code lang="eiffel">my_apple_box</code> is declared as a <code lang="eiffel">FOOD_BOX</code> which can contain only apples.
The entity <code lang="eiffel">my_apple_box</code> is declared as a <code lang="eiffel">FOOD_BOX</code> which can contain only apples.
Line 331: Line 361:
Of course, constraining a particular <code lang="eiffel">FOOD_BOX</code> to all types which are eatable is also allowed, and could be appropriate in certain cases, such as:
Of course, constraining a particular <code lang="eiffel">FOOD_BOX</code> to all types which are eatable is also allowed, and could be appropriate in certain cases, such as:


<lang eiffel>
<syntaxhighlight lang="eiffel">
my_refrigerator: FOOD_BOX [EATABLE]
my_refrigerator: FOOD_BOX [EATABLE]
</syntaxhighlight>
</lang>


Here's a small application that uses a <code lang="eiffel">FOOD_BOX</code> constrained to contain only apples:
Here's a small application that uses a <code lang="eiffel">FOOD_BOX</code> constrained to contain only apples:


<lang eiffel >
<syntaxhighlight lang="eiffel ">
class
class
APPLICATION
APPLICATION
Line 372: Line 402:
-- A pear
-- A pear
end
end
</syntaxhighlight>
</lang>


Notice that an instance of <code lang="eiffel">PEAR</code> is also created, and a line of code is present as a comment which would attempt to place the pear in the apple box:
Notice that an instance of <code lang="eiffel">PEAR</code> is also created, and a line of code is present as a comment which would attempt to place the pear in the apple box:


<lang eiffel>
<syntaxhighlight lang="eiffel">
-- my_apple_box.extend (one_pear)
-- my_apple_box.extend (one_pear)
</syntaxhighlight>
</lang>


If the comment mark "--" were removed from this line of code, an compile error would occur because of the attempt to violate <code lang="eiffel">my_apple_bos</code>'s constraint.
If the comment mark "--" were removed from this line of code, an compile error would occur because of the attempt to violate <code lang="eiffel">my_apple_bos</code>'s constraint.
Line 386: Line 416:
including inheritance relationships and interface implementation.
including inheritance relationships and interface implementation.
But for this task, the natural choice is an explicit member constraint.
But for this task, the natural choice is an explicit member constraint.
<lang fsharp>type ^a FoodBox // a generic type FoodBox
<syntaxhighlight lang="fsharp">type ^a FoodBox // a generic type FoodBox
when ^a: (member eat: unit -> string) // with an explicit member constraint on ^a,
when ^a: (member eat: unit -> string) // with an explicit member constraint on ^a,
(items:^a list) = // a one-argument constructor
(items:^a list) = // a one-argument constructor
Line 396: Line 426:


// an instance of a Banana FoodBox
// an instance of a Banana FoodBox
let someBananas = FoodBox [Banana(); Banana()]</lang>
let someBananas = FoodBox [Banana(); Banana()]</syntaxhighlight>


=={{header|Forth}}==
=={{header|Forth}}==
Line 404: Line 434:
Needs the FMS-SI (single inheritance) library code located here:
Needs the FMS-SI (single inheritance) library code located here:
http://soton.mpeforth.com/flag/fms/index.html
http://soton.mpeforth.com/flag/fms/index.html
<lang forth>include FMS-SI.f
<syntaxhighlight lang="forth">include FMS-SI.f
include FMS-SILib.f
include FMS-SILib.f

: (where) ( class-xt where-dfa -- flag )
swap >body { where-dfa class-dfa }
begin
class-dfa ['] object >body <>
while
class-dfa where-dfa = if true exit then
class-dfa sfa @ to class-dfa
repeat false ;

: where ( class-xt "classname" -- flag )
' >body state @
if postpone literal postpone (where)
else (where)
then ; immediate

:class Eatable
:class Eatable
:m eat cr ." successful eat" ;m
:m eat ." successful eat " ;m
;class
;class

\ FoodBox is defined without using eat in any way.
\ FoodBox is defined without inspecting for the eat message
:class FoodBox
:class FoodBox
object-list eatable-types
object-list eatable-types
:m fill: { n class-xt -- }
:m init: eatable-types init: ;m
:m add: ( obj -- )
class-xt where Eatable
dup is-kindOf Eatable
if n 0 do class-xt eatable-types xtadd: loop
else ." not an eatable type "
if eatable-types add:
else drop ." not an eatable type "
then ;m
then ;m
:m test
:m get ( -- obj ) eatable-types ;m
begin eatable-types each:
while eat
repeat ;m
;class
;class
FoodBox aFoodBox
Eatable aEatable
aEatable aFoodBox add: \ add the e1 object to the object-list
aFoodBox test \ => successful eat


:class brick
: test ( obj -- ) \ send the eat message to each object in the object-list
:m eat cr ." successful eat " ;m
begin dup each:
;class
while eat
repeat drop ;


brick abrick \ create an object that is not eatable
FoodBox fb
abrick aFoodBox add: \ => not an eatable type
3 ' Eatable fb fill: \ fill the object-list with 3 objects of class Eatable
fb get test
successful eat
successful eat
successful eat

FoodBox fb1
5 ' object fb1 fill: \ => not an eatable type


:class apple <super Eatable
:class apple <super Eatable
;class
;class


:class green-apple <super apple
apple anapple
anapple aFoodBox add:
;class
aFoodBox test \ => successful eat successful eat
</syntaxhighlight>


=={{header|Fortran}}==
5 ' green-apple fb1 fill:
In Fortran all checkes are done at compile time, in particular a dummy argument has to conform class.
fb1 get test
<syntaxhighlight lang="fortran">
successful eat
module cg
successful eat
implicit none
successful eat
successful eat
type, abstract :: eatable
successful eat
end type eatable
</lang>
type, extends(eatable) :: carrot_t
end type carrot_t
type :: brick_t; end type brick_t
type :: foodbox
class(eatable), allocatable :: food
contains
procedure, public :: add_item => add_item_fb
end type foodbox
contains

subroutine add_item_fb(this, f)
class(foodbox), intent(inout) :: this
class(eatable), intent(in) :: f
allocate(this%food, source=f)
end subroutine add_item_fb
end module cg


program con_gen
use cg
implicit none
type(carrot_t) :: carrot
type(brick_t) :: brick
type(foodbox) :: fbox
! Put a carrot into the foodbox
call fbox%add_item(carrot)
! Try to put a brick in - results in a compiler error
call fbox%add_item(brick)
end program con_gen

</syntaxhighlight>
{{out}}
ifort -o cg cg.f90
<pre>
cg.f90(40): error #6633: The type of the actual argument differs from the type of the dummy argument. [BRICK]
call fbox%add_item(brick)
</pre>
gfortran -o cg cg.f90
<pre>
cg.f90:41.23:

call fbox%add_item(brick)
1
Error: Type mismatch in argument 'f' at (1); passed TYPE(brick_t) to CLASS(eatable)

</pre>


=={{header|Go}}==
=={{header|Go}}==
Go's interfaces do exactly what this task wants.
Go's interfaces do exactly what this task wants.
Eatable looks like this:
Eatable looks like this:
<lang go>type eatable interface {
<syntaxhighlight lang="go">type eatable interface {
eat()
eat()
}</lang>
}</syntaxhighlight>
And the following is all it takes to define foodbox as a slice of eatables.
And the following is all it takes to define foodbox as a slice of eatables.
The result is that an object of type foodbox can hold objects of any type that implements the eat method (with the function signature specified in eatable.)
The result is that an object of type foodbox can hold objects of any type that implements the eat method (with the function signature specified in eatable.)
The definition of foodbox though, doesn't even need to enumerate the functions of eatable, much less call them. Whatever is in the interface is okay.
The definition of foodbox though, doesn't even need to enumerate the functions of eatable, much less call them. Whatever is in the interface is okay.
<lang go>type foodbox []eatable</lang>
<syntaxhighlight lang="go">type foodbox []eatable</syntaxhighlight>
Here is an example of an eatable type.
Here is an example of an eatable type.
<lang go>type peelfirst string
<syntaxhighlight lang="go">type peelfirst string


func (f peelfirst) eat() {
func (f peelfirst) eat() {
// peel code goes here
// peel code goes here
fmt.Println("mm, that", f, "was good!")
fmt.Println("mm, that", f, "was good!")
}</lang>
}</syntaxhighlight>
The only thing it takes to make peelfirst eatable is the definition of the eat method. When the eat method is defined, peelfirst automatically becomes an eatable. We say it ''satisfies'' the interface. Notice that "eatable" appears nowhere in the definition of peelfirst or the eat method of peelfirst.
The only thing it takes to make peelfirst eatable is the definition of the eat method. When the eat method is defined, peelfirst automatically becomes an eatable. We say it ''satisfies'' the interface. Notice that "eatable" appears nowhere in the definition of peelfirst or the eat method of peelfirst.


Here is a complete program using these types.
Here is a complete program using these types.
<lang go>package main
<syntaxhighlight lang="go">package main


import "fmt"
import "fmt"
Line 508: Line 579:
f0 := fb[0]
f0 := fb[0]
f0.eat()
f0.eat()
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 516: Line 587:
=={{header|Haskell}}==
=={{header|Haskell}}==
A ''type class'' defines a set of operations that must be implemented by a type:
A ''type class'' defines a set of operations that must be implemented by a type:
<lang haskell>class Eatable a where
<syntaxhighlight lang="haskell">class Eatable a where
eat :: a -> String</lang>
eat :: a -> String</syntaxhighlight>
We just require that instances of this type class implement a function <tt>eat</tt> which takes in the type and returns a string (I arbitrarily decided).
We just require that instances of this type class implement a function <tt>eat</tt> which takes in the type and returns a string (I arbitrarily decided).


The <tt>FoodBox</tt> type could be implemented as follows:
The <tt>FoodBox</tt> type could be implemented as follows:
<lang haskell>data (Eatable a) => FoodBox a = F [a]</lang>
<syntaxhighlight lang="haskell">data (Eatable a) => FoodBox a = F [a]</syntaxhighlight>
The stuff before the <tt>=></tt> specify what type classes the type variable <tt>a</tt> must belong to.
The stuff before the <tt>=></tt> specify what type classes the type variable <tt>a</tt> must belong to.


We can create an instance of <tt>Eatable</tt> at any time by providing an implementation for the function <tt>eat</tt>. Here we define a new type <tt>Banana</tt>, and make it an instance of <tt>Eatable</tt>.
We can create an instance of <tt>Eatable</tt> at any time by providing an implementation for the function <tt>eat</tt>. Here we define a new type <tt>Banana</tt>, and make it an instance of <tt>Eatable</tt>.
<lang haskell>data Banana = Foo -- the implementation doesn't really matter in this case
<syntaxhighlight lang="haskell">data Banana = Foo -- the implementation doesn't really matter in this case
instance Eatable Banana where
instance Eatable Banana where
eat _ = "I'm eating a banana"</lang>
eat _ = "I'm eating a banana"</syntaxhighlight>
We can declare existing types to be instances in the exact same way. The following makes <tt>Double</tt> an eatable type:
We can declare existing types to be instances in the exact same way. The following makes <tt>Double</tt> an eatable type:
<lang haskell>instance Eatable Double where
<syntaxhighlight lang="haskell">instance Eatable Double where
eat d = "I'm eating " ++ show d</lang>
eat d = "I'm eating " ++ show d</syntaxhighlight>
Another way to make an existing type eatable is to declare all instances of another type class instances of this one. Let's assume we have another type class <tt>Food</tt> which looks like this;
Another way to make an existing type eatable is to declare all instances of another type class instances of this one. Let's assume we have another type class <tt>Food</tt> which looks like this;
<lang haskell>class Food a where
<syntaxhighlight lang="haskell">class Food a where
munch :: a -> String</lang>
munch :: a -> String</syntaxhighlight>
Then we can make all instances of Food eatable using <tt>munch</tt> for <tt>eat</tt> with the following instance declaration:
Then we can make all instances of Food eatable using <tt>munch</tt> for <tt>eat</tt> with the following instance declaration:
<lang haskell>instance (Food a) => Eatable a where
<syntaxhighlight lang="haskell">instance (Food a) => Eatable a where
eat x = munch x</lang>
eat x = munch x</syntaxhighlight>


==Icon and {{header|Unicon}}==
==Icon and {{header|Unicon}}==
Line 543: Line 614:
In Unicon, new types can be defined as classes. The solution shown
In Unicon, new types can be defined as classes. The solution shown
follows the Scala approach.
follows the Scala approach.
<lang unicon>import Utils # From the UniLib package to get the Class class.
<syntaxhighlight lang="unicon">import Utils # From the UniLib package to get the Class class.


class Eatable:Class()
class Eatable:Class()
Line 565: Line 636:
if FoodBox([Fish("salmon")]) then write("Edible") else write("Inedible")
if FoodBox([Fish("salmon")]) then write("Edible") else write("Inedible")
if FoodBox([Rock("granite")]) then write("Edible") else write("Inedible")
if FoodBox([Rock("granite")]) then write("Edible") else write("Inedible")
end</lang>
end</syntaxhighlight>


Sample run:
Sample run:
Line 577: Line 648:
=={{header|J}}==
=={{header|J}}==
Implementation:
Implementation:
<lang j>coclass'Connoisseur'
<syntaxhighlight lang="j">coclass'Connoisseur'
isEdible=:3 :0
isEdible=:3 :0
0<nc<'eat__y'
0<nc<'eat__y'
Line 590: Line 661:
collection=: collection, y
collection=: collection, y
EMPTY
EMPTY
)</lang>
)</syntaxhighlight>
An edible type would be a class that has a verb with the name 'eat' (the task "eatable" requirement is checked on an object or class reference using the static method <code>isEdible_Connoisseur_</code>).
An edible type would be a class that has a verb with the name 'eat' (the task "eatable" requirement is checked on an object or class reference using the static method <code>isEdible_Connoisseur_</code>).


Line 596: Line 667:


For example:
For example:
<lang j>coclass'Apple'
<syntaxhighlight lang="j">coclass'Apple'
eat=:3 :0
eat=:3 :0
smoutput'delicious'
smoutput'delicious'
)</lang>
)</syntaxhighlight>
And here is a quicky demo of the above:
And here is a quicky demo of the above:
<syntaxhighlight lang="j">
<lang j>
lunch=:'' conew 'FoodBox'
lunch=:'' conew 'FoodBox'
a1=: conew 'Apple'
a1=: conew 'Apple'
Line 609: Line 680:
george=: conew 'Connoisseur'
george=: conew 'Connoisseur'
add__lunch george
add__lunch george
|inedible: assert</lang>
|inedible: assert</syntaxhighlight>


=={{header|Java}}==
=={{header|Java}}==
Line 616: Line 687:
Types which are Eatable would have to implement the
Types which are Eatable would have to implement the
<code>Eatable</code> interface and provide an <code>eat</code> method.
<code>Eatable</code> interface and provide an <code>eat</code> method.
<lang java5>interface Eatable
<syntaxhighlight lang="java5">interface Eatable
{
{
void eat();
void eat();
}</lang>
}</syntaxhighlight>
Type constraints in type parameters can be made via the <code>extends</code> keyword, indicating in this case that the type argument must be a type that is a subtype of <code>Eatable</code>.
Type constraints in type parameters can be made via the <code>extends</code> keyword, indicating in this case that the type argument must be a type that is a subtype of <code>Eatable</code>.
<lang java5>import java.util.List;
<syntaxhighlight lang="java5">import java.util.List;


class FoodBox<T extends Eatable>
class FoodBox<T extends Eatable>
{
{
public List<T> food;
public List<T> food;
}</lang>
}</syntaxhighlight>
Similarly a generic method can constrain its type parameters
Similarly a generic method can constrain its type parameters
<lang java5>public <T extends Eatable> void foo(T x) { }
<syntaxhighlight lang="java5">public <T extends Eatable> void foo(T x) { }
// although in this case this is no more useful than just "public void foo(Eatable x)"</lang>
// although in this case this is no more useful than just "public void foo(Eatable x)"</syntaxhighlight>
This <code>T</code> does not necessarily have to be defined in the class declaration. Another method may be declared like this:
This <code>T</code> does not necessarily have to be defined in the class declaration. Another method may be declared like this:
<lang java5>public class Test{
<syntaxhighlight lang="java5">public class Test{
public <T extends Eatable> void bar(){ }
public <T extends Eatable> void bar(){ }
}</lang>
}</syntaxhighlight>
which has no indication of where <code>T</code> is coming from. This method could be called like this:
which has no indication of where <code>T</code> is coming from. This method could be called like this:
<lang java5>test.<EatableClass>bar();</lang>
<syntaxhighlight lang="java5">test.<EatableClass>bar();</syntaxhighlight>
The <code>foo</code> method from before can figure out <code>T</code> from its parameter, but this <code>bar</code> method needs to be told what T is.
The <code>foo</code> method from before can figure out <code>T</code> from its parameter, but this <code>bar</code> method needs to be told what T is.

=={{header|Julia}}==
{{works with|Julia|0.6}}
Julia allows user defined types with inheritance. Misuse of a type generally produces a compile time error message.
<syntaxhighlight lang="julia">abstract type Edible end
eat(::Edible) = "Yum!"

mutable struct FoodBox{T<:Edible}
food::Vector{T}
end

struct Carrot <: Edible
variety::AbstractString
end

struct Brick
volume::Float64
end

c = Carrot("Baby")
b = Brick(125.0)
eat(c)
eat(b)</syntaxhighlight>

{{out}}
<pre>MethodError: no method matching eat(::Brick)
Closest candidates are:
eat(!Matched::Edible) at console:2</pre>

=={{header|Kotlin}}==
In the following program we define an interface, Eatable, and two classes - Cheese and Meat - which implement it and must therefore implement its eat() method because the interface itself does not provide a default implementation.

We then define a generic class, FoodBox, whose type parameter, T, is constrained to an Eatable type and instantiate it using both the Cheese and Meat types:
<syntaxhighlight lang="scala">// version 1.0.6

interface Eatable {
fun eat()
}

class Cheese(val name: String) : Eatable {
override fun eat() {
println("Eating $name")
}

override fun toString() = name
}

class Meat(val name: String) : Eatable {
override fun eat() {
println("Eating $name")
}

override fun toString() = name
}

class FoodBox<T: Eatable> {
private val foodList = mutableListOf<T>()

fun add(food: T) {
foodList.add(food)
}

override fun toString() = foodList.toString()
}

fun main(args: Array<String>) {
val cheddar = Cheese("cheddar")
val feta = Cheese("feta")
val cheeseBox = FoodBox<Cheese>()
cheeseBox.add(cheddar)
cheeseBox.add(feta)
println("CheeseBox contains : $cheeseBox")

val beef = Meat("beef")
val ham = Meat("ham")
val meatBox = FoodBox<Meat>()
meatBox.add(beef)
meatBox.add(ham)
println("MeatBox contains : $meatBox")

cheddar.eat()
beef.eat()
println("Full now!")
}</syntaxhighlight>

{{out}}
<pre>
CheeseBox contains : [cheddar, feta]
MeatBox contains : [beef, ham]
Eating cheddar
Eating beef
Full now!
</pre>


=={{header|Morfa}}==
=={{header|Morfa}}==
{{trans|D}}
{{trans|D}}
===Template Version===
===Template Version===
<lang morfa>import morfa.type.traits;
<syntaxhighlight lang="morfa">import morfa.type.traits;


template < T >
template < T >
Line 667: Line 831:
// var carBox: FoodBox< Car >; // Not allowed
// var carBox: FoodBox< Car >; // Not allowed
static assert( not trait(compiles, func() { var carBox: FoodBox< Car >; } ));
static assert( not trait(compiles, func() { var carBox: FoodBox< Car >; } ));
}</lang>
}</syntaxhighlight>




===Interface Version===
===Interface Version===


<lang morfa>interface IEdible
<syntaxhighlight lang="morfa">interface IEdible
{
{
public func eat(): void;
public func eat(): void;
Line 697: Line 861:
// var carBox: FoodBox< Car >; // Not allowed
// var carBox: FoodBox< Car >; // Not allowed
static assert( not trait(compiles, func() { var carBox: FoodBox< Car >; } ));
static assert( not trait(compiles, func() { var carBox: FoodBox< Car >; } ));
}</lang>
}</syntaxhighlight>


=={{header|Nemerle}}==
=={{header|Nemerle}}==
<lang Nemerle>using System.Collections.Generic;
<syntaxhighlight lang="nemerle">using System.Collections.Generic;


interface IEatable
interface IEatable
Line 745: Line 909:
}
}


foreach (apple in appleBox) apple.Eat();</lang>
foreach (apple in appleBox) apple.Eat();</syntaxhighlight>
{{out}}
{{out}}
<pre>nom..nom..nom
<pre>nom..nom..nom
Line 752: Line 916:


=={{header|Nim}}==
=={{header|Nim}}==
<lang nim>type
<syntaxhighlight lang="nim">type
Eatable = generic e
Eatable = concept e
eat(e)
eat(e)


Line 772: Line 936:


for f in fs:
for f in fs:
eat(f)</lang>
eat(f)</syntaxhighlight>

=={{header|Objeck}}==
All generic 'T' types associated with the FoodBox must implement the 'Eatable' interface. Generic constrains may either be an interface or a sub-classed type.
<syntaxhighlight lang="objeck">use Collection.Generic;

interface Eatable {
method : virtual : Eat() ~ Nil;
}

class FoodBox<T : Eatable> {
food : List<T>;
}

class Plum implements Eatable {
method : Eat() ~ Nil {
"Yummy Plum!"->PrintLine();
}
}

class Genericity {
function : Main(args : String[]) ~ Nil {
plums : FoodBox<Plum>;
}
}</syntaxhighlight>


=={{header|Objective-C}}==
=={{header|Objective-C}}==
Line 779: Line 967:
Types which are Eatable would have to implement the
Types which are Eatable would have to implement the
<code>Eatable</code> protocol and provide an <code>eat</code> method.
<code>Eatable</code> protocol and provide an <code>eat</code> method.
<lang objc>@protocol Eatable
<syntaxhighlight lang="objc">@protocol Eatable
- (void)eat;
- (void)eat;
@end</lang>
@end</syntaxhighlight>
Type constraints in type parameters can be made via the <code>:</code> keyword, indicating in this case that the type argument must be a type that is a subtype of <code>id<Eatable></code>.
Type constraints in type parameters can be made via the <code>:</code> keyword, indicating in this case that the type argument must be a type that is a subtype of <code>id<Eatable></code>.
<lang objc>@interface FoodBox<T : id<Eatable>> : NSObject
<syntaxhighlight lang="objc">@interface FoodBox<T : id<Eatable>> : NSObject
@end</lang>
@end</syntaxhighlight>


=={{header|OCaml}}==
=={{header|OCaml}}==
Line 790: Line 978:


A module type defines a set of operations that must be implemented by a module:
A module type defines a set of operations that must be implemented by a module:
<lang ocaml>module type Eatable = sig
<syntaxhighlight lang="ocaml">module type Eatable = sig
type t
type t
val eat : t -> unit
val eat : t -> unit
end</lang>
end</syntaxhighlight>
We just require that module instances of this module type describe a type <tt>t</tt> and implement a function <tt>eat</tt> which takes in the type and returns nothing.
We just require that module instances of this module type describe a type <tt>t</tt> and implement a function <tt>eat</tt> which takes in the type and returns nothing.


The <tt>FoodBox</tt> generic type could be implemented as a ''functor''
The <tt>FoodBox</tt> generic type could be implemented as a ''functor''
(something which takes a module as an argument and returns another module):
(something which takes a module as an argument and returns another module):
<lang ocaml>module MakeFoodBox(A : Eatable) = struct
<syntaxhighlight lang="ocaml">module MakeFoodBox(A : Eatable) = struct
type elt = A.t
type elt = A.t
type t = F of elt list
type t = F of elt list
let make_box_from_list xs = F xs
let make_box_from_list xs = F xs
end</lang>
end</syntaxhighlight>


We can create a module that is an instance of <tt>Eatable</tt> by specifying a type providing an implementation for the function <tt>eat</tt>. Here we define a module <tt>Banana</tt>, and make it an instance of <tt>Eatable</tt>.
We can create a module that is an instance of <tt>Eatable</tt> by specifying a type providing an implementation for the function <tt>eat</tt>. Here we define a module <tt>Banana</tt>, and make it an instance of <tt>Eatable</tt>.
<lang ocaml>type banana = Foo (* a dummy type *)
<syntaxhighlight lang="ocaml">type banana = Foo (* a dummy type *)


module Banana : Eatable with type t = banana = struct
module Banana : Eatable with type t = banana = struct
type t = banana
type t = banana
let eat _ = print_endline "I'm eating a banana"
let eat _ = print_endline "I'm eating a banana"
end</lang>
end</syntaxhighlight>


We can also create modules that use an existing type as its <code>t</code>. The following module uses <tt>float</tt> as its type:
We can also create modules that use an existing type as its <code>t</code>. The following module uses <tt>float</tt> as its type:
<lang ocaml>module EatFloat : Eatable with type t = float = struct
<syntaxhighlight lang="ocaml">module EatFloat : Eatable with type t = float = struct
type t = float
type t = float
let eat f = Printf.printf "I'm eating %f\n%!" f
let eat f = Printf.printf "I'm eating %f\n%!" f
end</lang>
end</syntaxhighlight>
Then, to make a FoodBox out of one of these modules, we need to call the functor on the module that specifies the type parameter:
Then, to make a FoodBox out of one of these modules, we need to call the functor on the module that specifies the type parameter:
<lang ocaml>module BananaBox = MakeFoodBox (Banana)
<syntaxhighlight lang="ocaml">module BananaBox = MakeFoodBox (Banana)
module FloatBox = MakeFoodBox (EatFloat)
module FloatBox = MakeFoodBox (EatFloat)


let my_box = BananaBox.make_box_from_list [Foo]
let my_box = BananaBox.make_box_from_list [Foo]
let your_box = FloatBox.make_box_from_list [2.3; 4.5]</lang>
let your_box = FloatBox.make_box_from_list [2.3; 4.5]</syntaxhighlight>
Unfortunately, it is kind of cumbersome in that, for every type parameter
Unfortunately, it is kind of cumbersome in that, for every type parameter
we want to use for this generic type, we will have to explicitly create a module
we want to use for this generic type, we will have to explicitly create a module
Line 834: Line 1,022:
Tests for identity need to be performed at runtime using mechanisms
Tests for identity need to be performed at runtime using mechanisms
such as the object isA method.
such as the object isA method.
<syntaxhighlight lang="oorexx">call dinnerTime "yogurt"
<lang ooRexx>
call dinnerTime "yogurt"
call dinnerTime .pizza~new
call dinnerTime .pizza~new
call dinnerTime .broccoli~new
call dinnerTime .broccoli~new
Line 863: Line 1,050:
return
return
end
end
else dish~eat
else dish~eat</syntaxhighlight>
{{out}}
</lang>
<pre>I can't eat that!

mmmmmmmm, pizza.
ugh, do I have to?.</pre>


=={{header|OxygenBasic}}==
=={{header|OxygenBasic}}==
Generic but not too generic I trust.
Generic but not too generic I trust.
<lang oxygenbasic>
<syntaxhighlight lang="oxygenbasic">
macro Gluttony(vartype, capacity, foodlist)
macro Gluttony(vartype, capacity, foodlist)
'==========================================
'==========================================
Line 955: Line 1,144:


print MrG.WeightGain 'result 15.75
print MrG.WeightGain 'result 15.75
</syntaxhighlight>
</lang>


=={{header|Perl 6}}==
=={{header|Phix}}==
{{libheader|Phix/Class}}
{{works with|Rakudo|2016.01}}
No interfaces per se, but you can explicitly test manually for these sort of things.
Needs 0.8.1+
=== using generic types ===
<syntaxhighlight lang="phix">include builtins\structs.e as structs


class foodbox
<lang perl6>subset Eatable of Any where { .^can('eat') };
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
class Cake { method eat() {...} }
string name
procedure eat()
printf(1,"mmm... %s\n",{this.name})
end procedure
end class
fruit banana = new({"banana"})


class clay
role FoodBox[Eatable] {
string name = "fletton"
has %.foodbox;
end class
}
clay brick = new()


lunchbox.add(banana)
class Yummy does FoodBox[Cake] { } # composes correctly
try
# class Yucky does FoodBox[Int] { } # fails to compose
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()</syntaxhighlight>
{{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.
<syntaxhighlight lang="phix">abstract class edible
string name
procedure eat(); -- (virtual)
end class


class foodbox2
my Yummy $foodbox .= new;
sequence contents = {}
say $foodbox.perl;</lang>
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()</syntaxhighlight>
{{out}}
{{out}}
<pre>
<lang>Yummy.new(foodbox => {})</lang>
test.exw line 8: type check failure, food is {"struct","clay2",8,1}
foodbox2 contains 2 items
mmm... banana
slurp... milkshake
</pre>


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<lang PicoLisp>(class +Eatable)
<syntaxhighlight lang="picolisp">(class +Eatable)


(dm eat> ()
(dm eat> ()
Line 994: Line 1,297:
(let (Box (new '(+FoodBox)) Eat (new '(+Eatable)) NoEat (new '(+Bla)))
(let (Box (new '(+FoodBox)) Eat (new '(+Eatable)) NoEat (new '(+Bla)))
(set> Box Eat) # Works
(set> Box Eat) # Works
(set> Box NoEat) ) # Gives an error</lang>
(set> Box NoEat) ) # Gives an error</syntaxhighlight>
{{out}}
{{out}}
<pre>$384320489 -- Object is not eatable
<pre>$384320489 -- Object is not eatable
Line 1,014: Line 1,317:
By doing so they will be forced to implement <code>eat</code>.
By doing so they will be forced to implement <code>eat</code>.


<lang racket>#lang racket
<syntaxhighlight lang="racket">#lang racket
(module+ test (require tests/eli-tester))
(module+ test (require tests/eli-tester))


Line 1,099: Line 1,402:
;; Show that you cannot make a food-box from the non-edible<%> semolina cannot
;; Show that you cannot make a food-box from the non-edible<%> semolina cannot
(implementation? semolina% edible<%>) => #f
(implementation? semolina% edible<%>) => #f
(new ((food-box-mixin semolina%) object%)) =error> exn:fail:contract?))</lang>
(new ((food-box-mixin semolina%) object%)) =error> exn:fail:contract?))</syntaxhighlight>


All the tests pass. Look at the tests to see what generates an exception (i.e.
All the tests pass. Look at the tests to see what generates an exception (i.e.
not allowed at runtime) and what does not.
not allowed at runtime) and what does not.

=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>subset Eatable of Any where { .^can('eat') };

class Cake { method eat() {...} }

role FoodBox[Eatable] {
has %.foodbox;
}

class Yummy does FoodBox[Cake] { } # composes correctly
# class Yucky does FoodBox[Int] { } # fails to compose

my Yummy $foodbox .= new;
say $foodbox;</syntaxhighlight>
{{out}}
<syntaxhighlight lang="text">Yummy.new(foodbox => {})</syntaxhighlight>


=={{header|Ruby}}==
=={{header|Ruby}}==
<lang ruby>class Foodbox
<syntaxhighlight lang="ruby">class Foodbox
def initialize (*food)
def initialize (*food)
raise ArgumentError, "food must be eadible" unless food.all?{|f| f.respond_to?(:eat)}
raise ArgumentError, "food must be eadible" unless food.all?{|f| f.respond_to?(:eat)}
Line 1,123: Line 1,444:
p Foodbox.new(Apple.new, "string can't eat")
p Foodbox.new(Apple.new, "string can't eat")
# => test1.rb:3:in `initialize': food must be eadible (ArgumentError)
# => test1.rb:3:in `initialize': food must be eadible (ArgumentError)
</syntaxhighlight>
</lang>

=={{header|Rust}}==
<syntaxhighlight lang="rust">
// This declares the "Eatable" constraint. It could contain no function.
trait Eatable {
fn eat();
}

// This declares the generic "FoodBox" type,
// whose parameter must satisfy the "Eatable" constraint.
// The objects of this type contain a vector of eatable objects.
struct FoodBox<T: Eatable> {
_data: Vec<T>,
}

// This implements the functions associated with the "FoodBox" type.
// This statement is not required, but here it is used
// to declare a handy "new" constructor.
impl<T: Eatable> FoodBox<T> {
fn new() -> FoodBox<T> {
FoodBox::<T> { _data: Vec::<T>::new() }
}
}

// This declares a simple type.
struct Banana {}

// This makes the "Banana" type satisfy the "Eatable" constraint.
// For that, every declaration inside the declaration of "Eatable"
// must be implemented here.
impl Eatable for Banana {
fn eat() {}
}

// This makes also the primitive "char" type satisfy the "Eatable" constraint.
impl Eatable for char {
fn eat() {}
}

fn main() {
// This instantiate a "FoodBox" parameterized by the "Banana" type.
// It is allowed as "Banana" implements "Eatable".
let _fb1 = FoodBox::<Banana>::new();

// This instantiate a "FoodBox" parameterized by the "char" type.
// It is allowed, as "char" implements "Eatable".
let _fb2 = FoodBox::<char>::new();

// This instantiate a "FoodBox" parameterized by the "bool" type.
// It is NOT allowed, as "bool" does not implement "Eatable".
//let _fb3 = FoodBox::<bool>::new();
}
</syntaxhighlight>


=={{header|Sather}}==
=={{header|Sather}}==
<lang sather>abstract class $EDIBLE is
<syntaxhighlight lang="sather">abstract class $EDIBLE is
eat;
eat;
end;
end;
Line 1,176: Line 1,550:
loop box.elt!.eat; end;
loop box.elt!.eat; end;
end;
end;
end;</lang>
end;</syntaxhighlight>
The GNU Sather compiler v1.2.3 let the "box2" pass, even though it shouldn't. Read e.g. [http://www.gnu.org/software/sather/docs-1.2/tutorial/parameterized1751.html this tutorial's section]
The GNU Sather compiler v1.2.3 let the "box2" pass, even though it shouldn't. Read e.g. [http://www.gnu.org/software/sather/docs-1.2/tutorial/parameterized1751.html this tutorial's section]


Line 1,183: Line 1,557:
This specific constrain, for the type to contain a particular method,
This specific constrain, for the type to contain a particular method,
can be written as this:
can be written as this:
<lang scala>type Eatable = { def eat: Unit }
<syntaxhighlight lang="scala">type Eatable = { def eat: Unit }


class FoodBox(coll: List[Eatable])
class FoodBox(coll: List[Eatable])
Line 1,193: Line 1,567:
}
}


val foodBox = new FoodBox(List(new Fish("salmon")))</lang>
val foodBox = new FoodBox(List(new Fish("salmon")))</syntaxhighlight>
A more extensive discussion on genericity in Scala and some of the constrains
A more extensive discussion on genericity in Scala and some of the constrains
that can be imposed can be found on [[Parametric Polymorphism]].
that can be imposed can be found on [[Parametric Polymorphism]].

=={{header|Sidef}}==
<syntaxhighlight lang="ruby">class FoodBox(*food { .all { .respond_to(:eat) } }) { }

class Fruit { method eat { ... } }
class Apple < Fruit { }

say FoodBox(Fruit(), Apple()).dump #=> FoodBox(food: [Fruit(), Apple()])
say FoodBox(Apple(), "foo") #!> ERROR: class `FoodBox` !~ (Apple, String)</syntaxhighlight>


=={{header|Swift}}==
=={{header|Swift}}==
Line 1,201: Line 1,584:
Types which are Eatable would have to conform to the <code>Eatable</code> protocol
Types which are Eatable would have to conform to the <code>Eatable</code> protocol
and provide an <code>eat</code> method.
and provide an <code>eat</code> method.
<lang swift>protocol Eatable {
<syntaxhighlight lang="swift">protocol Eatable {
func eat()
func eat()
}</lang>
}</syntaxhighlight>
Type constraints in type parameters can be made via the <code>:</code> syntax, indicating in this case that the type argument must be a type that is
Type constraints in type parameters can be made via the <code>:</code> syntax, indicating in this case that the type argument must be a type that is
a subtype of <code>Eatable</code>.
a subtype of <code>Eatable</code>.
<lang swift>struct FoodBox<T: Eatable> {
<syntaxhighlight lang="swift">struct FoodBox<T: Eatable> {
var food: [T]
var food: [T]
}</lang>
}</syntaxhighlight>
Similarly a generic function or method can constrain its type parameters
Similarly a generic function or method can constrain its type parameters
<lang swift>func foo<T: Eatable>(x: T) { }
<syntaxhighlight lang="swift">func foo<T: Eatable>(x: T) { }
// although in this case this is no more useful than just "func foo(x: Eatable)"</lang>
// although in this case this is no more useful than just "func foo(x: Eatable)"</syntaxhighlight>

=={{header|TXR}}==

===Macro wrapper for <code>defstruct</code>===

We implement a food-box-defining macro, which checks at macro expansion time that the contained type is <code>edible</code>. The macro generates a structure of the specified name, which has a <code>set-food</code> method that additionally performs a run-time check against the exact variant of the <code>edible</code> type that was given to the macro.

<syntaxhighlight lang="txrlisp">(defmacro define-food-box (name food-type : supers . clauses)
(unless (subtypep food-type 'edible)
(error "~s requires edible type, not ~s" %fun% food-type))
^(defstruct ,name ,supers
food
(:method set-food (me food)
(unless (typep food ',food-type)
(error "~s: requires ~s object, not ~s" %fun% ',food-type food))
(set me.food food))
,*clauses))</syntaxhighlight>

Instead of the type-based <code>subtypep</code> check, we could easily check for the existence of methods; e.g. test for the presence of a static slot using <code>(static-slot-p food-type 'eat)</code>, or more specifically that it's a function: <code>(functionp (static-slot food-type 'eat))</code>. These tests will blow up if the macro's <code>food-type</code> argument isn't a struct type.

In the interactive session below, we:

* verify that <code>define-food-box</code> cannot be used with a type argument that isn't derived from <code>edible</code>
* define the struct type <code>edible</code> and then one derived from it called <code>perishable</code>.
* use <code>define-food-box</code> to define a box called <code>fridge</code> which holds <code>perishable</code>. This works because <code>perishable</code> is <code>edible</code>
* create an instance of <code>fridge</code> and show that its <code>set-food</code> method doesn't take an integer, or an <code>edible</code>; only a <code>perishable</code>.

{{out}}

<pre>$ txr -i generic.tl
This area is under 24 hour TTY surveillance.
1> (define-food-box fridge string)
** define-food-box requires edible type, not string
** during evaluation of form (error "~s requires edible type, not ~s"
'define-food-box
food-type)
** ... an expansion of (error "~s requires edible type, not ~s"
%fun% food-type)
** which is located at generic.tl:3
1> (defstruct edible ())
#<struct-type edible>
2> (defstruct perishable (edible))
#<struct-type perishable>
3> (define-food-box fridge perishable)
#<struct-type fridge>
4> (new fridge)
#S(fridge food nil)
5> *4.(set-food 42)
** (set-food fridge): requires perishable object, not 42
** during evaluation of form (error "~s: requires ~s object, not ~s"
'(set-food fridge)
'perishable
food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
%fun% 'perishable
food)
** which is located at expr-3:1
5> *4.(set-food (new edible))
** (set-food fridge): requires perishable object, not #S(edible)
** during evaluation of form (error "~s: requires ~s object, not ~s"
'(set-food fridge)
'perishable
food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
%fun% 'perishable
food)
** which is located at expr-3:1
5> *4.(set-food (new perishable))
#S(perishable)
6> *4
#S(fridge food #S(perishable))</pre>

===Custom <code>defstruct</code> clause===

Wrapping <code>defstruct</code> is a heavy-handed approach that may be difficult to retrofit into an existing code base. One possible issue is that two developers write such a macro, and then someone needs to use both of them for the same class. But each macro wants to write its own entire <code>defstruct</code> form.

Here, we instead use a custom clause to inject the <code>food</code> slot, <code>set-food</code> method, and the static and dynamic checks. The mechanisms remain identical.

<syntaxhighlight lang="txrlisp">(define-struct-clause :food-box (food-type :form form)
(unless (subtypep food-type 'edible)
(compile-error form "~s requires edible type, not ~s" :food-box food-type))
^(food
(:method set-food (me food)
(unless (typep food ',food-type)
(error "~s: requires ~s object, not ~s" %fun% ',food-type food))
(set me.food food))))</syntaxhighlight>

{{out}}

<pre>$ txr -i generic.tl
Apply today for a TXR credit card, and get 1MB off your next allocation.
1> (defstruct fridge ()
(:food-box string))
** expr-1:1: defstruct: :food-box requires edible type, not string
1> (defstruct edible ())
#<struct-type edible>
2> (defstruct perishable (edible))
#<struct-type perishable>
3> (defstruct fridge ()
(:food-box perishable))
#<struct-type fridge>
4> (new fridge)
#S(fridge food nil)
5> *4.(set-food 42)
** (set-food fridge): requires perishable object, not 42
** during evaluation of form (error "~s: requires ~s object, not ~s"
'(set-food fridge)
'perishable
food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
%fun% 'perishable
food)
** which is located at expr-3:1
5> *4.(set-food (new edible))
** (set-food fridge): requires perishable object, not #S(edible)
** during evaluation of form (error "~s: requires ~s object, not ~s"
'(set-food fridge)
'perishable
food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
%fun% 'perishable
food)
** which is located at expr-3:1
5> *4.(set-food (new perishable))
#S(perishable)</pre>

=={{header|Wren}}==
Wren is dynamically typed and so any constraint on class instantiation can only be checked at run time.
<syntaxhighlight lang="wren">// abstract class
class Eatable {
eat() { /* override in child class */ }
}

class FoodBox {
construct new(contents) {
if (contents.any { |e| !(e is Eatable) }) {
Fiber.abort("All FoodBox elements must be eatable.")
}
_contents = contents
}

contents { _contents }
}

// Inherits from Eatable and overrides eat() method.
class Pie is Eatable {
construct new(filling) { _filling = filling }

eat() { System.print("%(_filling) pie, yum!") }
}

// Not an Eatable.
class Bicycle {
construct new() {}
}

var items = [Pie.new("Apple"), Pie.new("Gooseberry")]
var fb = FoodBox.new(items)
fb.contents.each { |item| item.eat() }
System.print()
items.add(Bicycle.new())
fb = FoodBox.new(items) // throws an error because Bicycle not eatable</syntaxhighlight>

{{out}}
<pre>
Apple pie, yum!
Gooseberry pie, yum!

All FoodBox elements must be eatable.
[./constrained_genericity line 9] in init new(_)
[./constrained_genericity line 12] in
[./constrained_genericity line 34] in (script)
</pre>


=={{header|zkl}}==
=={{header|zkl}}==
Line 1,217: Line 1,773:


This is a slightly different take on the task, keeping the editables and rejecting the garbage.
This is a slightly different take on the task, keeping the editables and rejecting the garbage.
<lang zkl>class Eatable{ var v;
<syntaxhighlight lang="zkl">class Eatable{ var v;
fcn eat{ println("munching ",self.topdog.name); }
fcn eat{ println("munching ",self.topdog.name); }
}
}
Line 1,226: Line 1,782:
if(garbage) println("Rejecting: ",garbage);
if(garbage) println("Rejecting: ",garbage);
}
}
}</lang>
}</syntaxhighlight>
<lang zkl>class Apple(Eatable){} class Nuts(Eatable){} class Foo{}
<syntaxhighlight lang="zkl">class Apple(Eatable){} class Nuts(Eatable){} class Foo{}
FoodBox(Apple,"boogers",Nuts,Foo).contents.apply2("eat");</lang>
FoodBox(Apple,"boogers",Nuts,Foo).contents.apply2("eat");</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,237: Line 1,793:


<!-- Place omit from templates below here -->
<!-- Place omit from templates below here -->
{{omit from|360 Assembly|not statically typed}}
{{omit from|6502 Assembly|not statically typed}}
{{omit from|68000 Assembly|not statically typed}}
{{omit from|8051 Assembly|not statically typed}}
{{omit from|8080 Assembly|not statically typed}}
{{omit from|8086 Assembly|not statically typed}}
{{omit from|AArch64 Assembly|not statically typed}}
{{omit from|ALGOL 68|it isn't immediately obvious that ALGOL 68 is object oriented}}
{{omit from|ALGOL 68|it isn't immediately obvious that ALGOL 68 is object oriented}}
{{omit from|ARM Assembly|not statically typed}}
{{omit from|BBC BASIC}}
{{omit from|BBC BASIC}}
{{omit from|C|type system doesn't support this}}
{{omit from|C|type system doesn't support this}}
Line 1,246: Line 1,810:
{{omit from|Mathematica}}
{{omit from|Mathematica}}
{{omit from|Maxima}}
{{omit from|Maxima}}
{{omit from|MIPS Assembly|not statically typed}}
{{omit from|Perl|not statically typed}}
{{omit from|Perl|not statically typed}}
{{omit from|Phix}}
{{omit from|Python|not statically typed}}
{{omit from|Python|not statically typed}}
{{omit from|Ruby|not statically typed}}
{{omit from|Ruby|not statically typed}}
Line 1,257: Line 1,821:
{{omit from|Scheme|not statically typed}}
{{omit from|Scheme|not statically typed}}
{{omit from|Clojure|not statically typed}}
{{omit from|Clojure|not statically typed}}
{{omit from|x86 Assembly|not statically typed}}
{{omit from|Z80 Assembly|not statically typed}}
{{omit from|ZX Spectrum Basic|Does not support user defined datatypes}}
{{omit from|ZX Spectrum Basic|Does not support user defined datatypes}}

Revision as of 17:02, 20 November 2023

Task
Constrained genericity
You are encouraged to solve this task according to the task description, using any language you may know.

Constrained genericity or bounded quantification means that a parametrized type or function (see parametric polymorphism) can only be instantiated on types fulfilling some conditions, even if those conditions are not used in that function.

Say a type is called "eatable" if you can call the function eat on it. Write a generic type FoodBox which contains a collection of objects of a type given as parameter, but can only be instantiated on eatable types. The FoodBox shall not use the function eat in any way (i.e. without the explicit restriction, it could be instantiated on any type). The specification of a type being eatable should be as generic as possible in your language (i.e. the restrictions on the implementation of eatable types should be as minimal as possible). Also explain the restrictions, if any, on the implementation of eatable types, and show at least one example of an eatable type.

Ada

Ada allows various constraints to be specified in parameters of generics. A formal type constrained to be derived from certain base is one of them:

with Ada.Containers.Indefinite_Vectors;

package Nutrition is
   type Food is interface;
   procedure Eat (Object : in out Food) is abstract;

end Nutrition;

with Ada.Containers;
with Nutrition;

generic
   type New_Food is new Nutrition.Food;
package Food_Boxes is

  package Food_Vectors is
      new Ada.Containers.Indefinite_Vectors
          (  Index_Type   => Positive,
             Element_Type => New_Food
          );

   subtype Food_Box is Food_Vectors.Vector;

end Food_Boxes;

The package Nutrition defines an interface of an eatable object, that is, the procedure Eat. Then a generic container package is defined with the elements to be of some type derived from Food. Example of use:

type Banana is new Food with null record;
overriding procedure Eat (Object : in out Banana) is null;
package Banana_Box is new Food_Boxes (Banana);

type Tomato is new Food with null record;
overriding procedure Eat (Object : in out Tomato) is null;
package Tomato_Box is new Food_Boxes (Tomato);
-- We have declared Banana and Tomato as a Food.

The Tomato_Box can only contain tomatoes; the Banana_Box can only contain bananas. You can only create boxes of eatable objects.

C#

In C#, type constraints are made on the type hierarchy, so here we make IEatable an interface, with an Eat method. Types which are eatable would have to implement the IEatable interface and provide an Eat method.

interface IEatable
{
    void Eat();
}

Type constraints in type parameters can be made via the where keyword, which allows us to qualify T. In this case, we indicate that the type argument must be a type that is a subtype of IEatable.

using System.Collections.Generic;

class FoodBox<T> where T : IEatable
{
    List<T> food;
}

For example, an eatable Apple:

class Apple : IEatable
{
    public void Eat()
    {
        System.Console.WriteLine("Apple has been eaten");
    }
}

C# also has the interesting functionality of being able to require that a generic type have a default constructor. This means that the generic type can actually instantiate the objects without ever knowing the concrete type. To do so, we constrain the where clause with an additional term "new()". This must come after any other constraints. In this example, any type with a default constructor that implements IEatable is allowed.

using System.Collections.Generic

class FoodMakingBox<T> where T : IEatable, new()
{
    List<T> food;

    void Make(int numberOfFood)
    {
        this.food = new List<T>();
        for (int i = 0; i < numberOfFood; i++)
        {
            this.food.Add(new T());
        }
    }
}

C++

Works with: C++11

Uses static assertion to disallow instantiations on incorrect types

template<typename T> //Detection helper struct
struct can_eat       //Detects presence of non-const member function void eat()
{
  private:
    template<typename U, void (U::*)()> struct SFINAE {};
    template<typename U> static char Test(SFINAE<U, &U::eat>*);
    template<typename U> static int Test(...);
  public:
    static constexpr bool value = sizeof(Test<T>(0)) == sizeof(char);
};

struct potato
{ void eat(); };

struct brick
{};

template<typename T>
class FoodBox
{
    //Using static assertion to prohibit non-edible types
    static_assert(can_eat<T>::value, "Only edible items are allowed in foodbox");

    //Rest of class definition
};

int main()
{
    FoodBox<potato> lunch;

    //Following leads to compile-time error
    //FoodBox<brick> practical_joke;
}

Common Lisp

The technique used here is like that in the Abstract type task.

The task says that this task is only for statically typed languages, and Common Lisp is dynamically typed. However, there are many places where type declarations can be provided to the compiler, and there is user access to the type system (e.g., a user can ask whether an object is of a particular type). Via the latter mechanism, one could write a class containing a collection such that the insert method checked that the object to be inserted is of an appropriate type.

In this example, we define a class food, and two subclasses, inedible-food and edible-food. We define a generic function eat, and specialize it only for edible-food. We then define a predicate eatable-p which returns true only on objects for which eat methods have been defined. Then, using deftype with a satisfies type specifier, we define a type eatable to which only objects satisfying eatable-p belong. Finally, we define a function make-food-box which takes, in addition to typical array creation arguments, a type specifier. The array is declared to have elements of the type that is the intersection of food and the provided type. make-eatable-food-box simply calls make-food-box with the type eatable.

The only shortcoming here is that the compiler isn't required to enforce the type specifications for the arrays. A custom insert function, however, could remember the specified type for the collection, and assert that inserted elements are of that type.

(defclass food () ())

(defclass inedible-food (food) ())

(defclass edible-food (food) ())

(defgeneric eat (foodstuff)
  (:documentation "Eat the foodstuff."))

(defmethod eat ((foodstuff edible-food))
  "A specialized method for eating edible-food."
  (format nil "Eating ~w." foodstuff))

(defun eatable-p (thing)
  "Returns true if there are eat methods defined for thing."
  (not (endp (compute-applicable-methods #'eat (list thing)))))

(deftype eatable ()
  "Eatable objects are those satisfying eatable-p."
  '(satisfies eatable-p))

(defun make-food-box (extra-type &rest array-args)
  "Returns an array whose element-type is (and extra-type food).
array-args should be suitable for MAKE-ARRAY, and any provided
element-type keyword argument is ignored."
  (destructuring-bind (dimensions &rest array-args) array-args
    (apply 'make-array dimensions
           :element-type `(and ,extra-type food)
           array-args)))

(defun make-eatable-food-box (&rest array-args)
  "Return an array whose elements are declared to be of type (and
eatable food)."
  (apply 'make-food-box 'eatable array-args))

Crystal

Similar to Ruby version, but shows error at compile-time.

class Apple
  def eat
  end
end

class Carrot
  def eat
  end
end

class FoodBox(T)
  def initialize(@data : Array(T))
    {% if T.union? %}
    {% raise "All items should be eatable" unless T.union_types.all? &.has_method?(:eat) %}
    {% else %}
    {% raise "Items should be eatable" unless T.has_method?(:eat) %}
    {% end %}
  end
end

FoodBox.new([Apple.new, Apple.new])
FoodBox.new([Apple.new, Carrot.new])
FoodBox.new([Apple.new, Carrot.new, 123])
Output:
Error in line 23: All items should be eatable

D

Template Version

enum IsEdible(T) = is(typeof(T.eat));

struct FoodBox(T) if (IsEdible!T) {
    T[] food;
    alias food this;
}

struct Carrot {
    void eat() {}
}

static struct Car {}

void main() {
    FoodBox!Carrot carrotsBox; // OK
    carrotsBox ~= Carrot();    // Adds a carrot

    //FoodBox!Car carsBox;     // Not allowed
}

Interface Version

interface IEdible { void eat(); }

struct FoodBox(T : IEdible) {
    T[] food;
    alias food this;
}

class Carrot : IEdible {
    void eat() {}
}

class Car {}

void main() {
    FoodBox!Carrot carrotBox; // OK
    //FoodBox!Car carBox;     // Not allowed
}

E

It is surely arguable whether this constitutes an implementation of the above task:

/** Guard accepting only objects with an 'eat' method */
def Eatable {
    to coerce(specimen, ejector) {
        if (Ref.isNear(specimen) && specimen.__respondsTo("eat", 0)) {
            return specimen
        } else {
            throw.eject(ejector, `inedible: $specimen`)
        }
    }
}

def makeFoodBox() {
    return [].diverge(Eatable) # A guard-constrained list
}

Eiffel

Eiffel has included support for constrained genericty since its earliest implementations (as shown in Bertrand Meyer's paper from OOPSLA '86, available online.)

The "eatable" characteristic is modeled by a deferred class (deferred classes are similar to abstract classes in some other languages).

deferred class
    EATABLE

feature -- Basic operations

    eat
            -- Eat this eatable substance
        deferred
        end
end

Class EATABLE can then be inherited by any other class, with the understanding that the inheriting class will have to provide an implementation for the procedure eat. Here are two such classes, APPLE and PEAR:

class
    APPLE

inherit
    EATABLE

feature -- Basic operations

    eat
            -- Consume
        do
            print ("One apple eaten%N")
        end
end


class
    PEAR

inherit
    EATABLE

feature -- Basic operations

    eat
            -- Consume
        do
            print ("One pear eaten%N")
        end
end

Instances of the generic class FOOD_BOX can contain any types of EATABLE items. The constraint is shown in the formal generics part of the class declaration for FOOD_BOX:

class
    FOOD_BOX [G -> EATABLE]

inherit
    ARRAYED_LIST [G]

create
    make

end

So, any declaration of type FOOD_BOX can constrain its contents to any particular eatable type. For example:

    my_apple_box: FOOD_BOX [APPLE]

The entity my_apple_box is declared as a FOOD_BOX which can contain only apples.

Of course, constraining a particular FOOD_BOX to all types which are eatable is also allowed, and could be appropriate in certain cases, such as:

    my_refrigerator: FOOD_BOX [EATABLE]

Here's a small application that uses a FOOD_BOX constrained to contain only apples:

class
    APPLICATION

create
    make

feature {NONE} -- Initialization

    make
            -- Run application.
        do
            create my_apple_box.make (10)
            create one_apple
            create one_pear
            my_apple_box.extend (one_apple)
--          my_apple_box.extend (one_pear)
            across
                my_apple_box as ic
            loop
                ic.item.eat
            end
        end

feature -- Access

    my_apple_box: FOOD_BOX [APPLE]
            -- My apple box

    one_apple: APPLE
            -- An apple

    one_pear: PEAR
            -- A pear
end

Notice that an instance of PEAR is also created, and a line of code is present as a comment which would attempt to place the pear in the apple box:

--              my_apple_box.extend (one_pear)

If the comment mark "--" were removed from this line of code, an compile error would occur because of the attempt to violate my_apple_bos's constraint.

F#

It is possible to constrain type parameters in a number of ways, including inheritance relationships and interface implementation. But for this task, the natural choice is an explicit member constraint.

type ^a FoodBox                         // a generic type FoodBox
  when ^a: (member eat: unit -> string) // with an explicit member constraint on ^a,
  (items:^a list) =                     // a one-argument constructor
  member inline x.foodItems = items     // and a public read-only property

// a class type that fullfills the member constraint
type Banana() =
  member x.eat() = "I'm eating a banana."

// an instance of a Banana FoodBox
let someBananas = FoodBox [Banana(); Banana()]

Forth

Works with: Forth

Works with any ANS Forth

Needs the FMS-SI (single inheritance) library code located here: http://soton.mpeforth.com/flag/fms/index.html

include FMS-SI.f
include FMS-SILib.f
:class Eatable
   :m eat ." successful eat " ;m
;class
 
\ FoodBox is defined without inspecting for the eat message
:class FoodBox
  object-list eatable-types
  :m init: eatable-types init: ;m
  :m add: ( obj -- )
     dup is-kindOf Eatable 
     if   eatable-types add:
     else drop ." not an eatable type " 
     then ;m
  :m test 
     begin eatable-types each:
     while eat
     repeat ;m
;class
 
FoodBox aFoodBox 
Eatable aEatable 
aEatable aFoodBox add:  \ add the e1 object to the object-list
aFoodBox test  \ => successful eat

:class brick
 :m eat cr ." successful eat " ;m 
;class

brick abrick  \ create an object that is not eatable 
abrick aFoodBox add: \ => not an eatable type 

:class apple <super Eatable
;class 

apple anapple  
anapple aFoodBox add: 
aFoodBox test  \ => successful eat successful eat

Fortran

In Fortran all checkes are done at compile time, in particular a dummy argument has to conform class.

module cg
    implicit none
    
    type, abstract :: eatable
    end type eatable
    
    type, extends(eatable) :: carrot_t
    end type carrot_t
    
    type :: brick_t; end type brick_t
    
    type :: foodbox
	class(eatable), allocatable :: food
    contains
        procedure, public :: add_item => add_item_fb
    end type foodbox
    
contains

    subroutine add_item_fb(this, f)
        class(foodbox), intent(inout) :: this
        class(eatable), intent(in)    :: f
        allocate(this%food, source=f)
    end subroutine add_item_fb
end module cg


program con_gen
    use cg
    implicit none
    
    type(carrot_t) :: carrot
    type(brick_t)  :: brick
    type(foodbox)  :: fbox
    
    ! Put a carrot into the foodbox
    call fbox%add_item(carrot)
    
    ! Try to put a brick in - results in a compiler error
    call fbox%add_item(brick)
    
end program con_gen
Output:

ifort -o cg cg.f90

cg.f90(40): error #6633: The type of the actual argument differs from the type of the dummy argument.   [BRICK]
    call fbox%add_item(brick)

gfortran -o cg cg.f90

cg.f90:41.23:

    call fbox%add_item(brick)
                       1
Error: Type mismatch in argument 'f' at (1); passed TYPE(brick_t) to CLASS(eatable)

Go

Go's interfaces do exactly what this task wants. Eatable looks like this:

type eatable interface {
    eat()
}

And the following is all it takes to define foodbox as a slice of eatables. The result is that an object of type foodbox can hold objects of any type that implements the eat method (with the function signature specified in eatable.) The definition of foodbox though, doesn't even need to enumerate the functions of eatable, much less call them. Whatever is in the interface is okay.

type foodbox []eatable

Here is an example of an eatable type.

type peelfirst string

func (f peelfirst) eat() {
    // peel code goes here
    fmt.Println("mm, that", f, "was good!")
}

The only thing it takes to make peelfirst eatable is the definition of the eat method. When the eat method is defined, peelfirst automatically becomes an eatable. We say it satisfies the interface. Notice that "eatable" appears nowhere in the definition of peelfirst or the eat method of peelfirst.

Here is a complete program using these types.

package main

import "fmt"

type eatable interface {
    eat()
}

type foodbox []eatable

type peelfirst string

func (f peelfirst) eat() {
    // peel code goes here
    fmt.Println("mm, that", f, "was good!")
}

func main() {
    fb := foodbox{peelfirst("banana"), peelfirst("mango")}
    f0 := fb[0]
    f0.eat()
}
Output:
mm, that banana was good!

Haskell

A type class defines a set of operations that must be implemented by a type:

class Eatable a where
  eat :: a -> String

We just require that instances of this type class implement a function eat which takes in the type and returns a string (I arbitrarily decided).

The FoodBox type could be implemented as follows:

data (Eatable a) => FoodBox a = F [a]

The stuff before the => specify what type classes the type variable a must belong to.

We can create an instance of Eatable at any time by providing an implementation for the function eat. Here we define a new type Banana, and make it an instance of Eatable.

data Banana = Foo -- the implementation doesn't really matter in this case
instance Eatable Banana where
  eat _ = "I'm eating a banana"

We can declare existing types to be instances in the exact same way. The following makes Double an eatable type:

instance Eatable Double where
  eat d = "I'm eating " ++ show d

Another way to make an existing type eatable is to declare all instances of another type class instances of this one. Let's assume we have another type class Food which looks like this;

class Food a where
  munch :: a -> String

Then we can make all instances of Food eatable using munch for eat with the following instance declaration:

instance (Food a) => Eatable a where
  eat x = munch x

Icon and Unicon

Neither Icon nor Unicon are statically typed. In Unicon, new types can be defined as classes. The solution shown follows the Scala approach.

import Utils        # From the UniLib package to get the Class class.

class Eatable:Class()
end

class Fish:Eatable(name)
    method eat(); write("Eating "+name); end
end

class Rock:Class(name)
    method eat(); write("Eating "+name); end
end

class FoodBox(A)
initially
    every item := !A do if "Eatable" == item.Type() then next else bad := "yes" 
    return /bad
end

procedure main()
    if FoodBox([Fish("salmon")]) then write("Edible") else write("Inedible")
    if FoodBox([Rock("granite")]) then write("Edible") else write("Inedible")
end

Sample run:

->cg
Edible
Inedible
->

J

Implementation:

coclass'Connoisseur'
isEdible=:3 :0
  0<nc<'eat__y'
)

coclass'FoodBox'
create=:3 :0
  collection=: 0#y
)
add=:3 :0"0
  'inedible' assert isEdible_Connoisseur_ y
  collection=: collection, y
  EMPTY
)

An edible type would be a class that has a verb with the name 'eat' (the task "eatable" requirement is checked on an object or class reference using the static method isEdible_Connoisseur_).

We have also defined a 'FoodBox' container class which can only contain edible objects. (Our add method returns returns an empty result since its purpose is to add to the container, not to produce a result.)

For example:

coclass'Apple'
eat=:3 :0
  smoutput'delicious'
)

And here is a quicky demo of the above:

   lunch=:'' conew 'FoodBox'
   a1=: conew 'Apple'
   a2=: conew 'Apple'
   add__lunch a1
   add__lunch a2
   george=: conew 'Connoisseur'
   add__lunch george
|inedible: assert

Java

Works with: Java version 5

In Java type constraints are made on the type hierarchy, so here we make Eatable an interface, with an eat method. Types which are Eatable would have to implement the Eatable interface and provide an eat method.

interface Eatable
{
    void eat();
}

Type constraints in type parameters can be made via the extends keyword, indicating in this case that the type argument must be a type that is a subtype of Eatable.

import java.util.List;

class FoodBox<T extends Eatable>
{
    public List<T> food;
}

Similarly a generic method can constrain its type parameters

public <T extends Eatable> void foo(T x) { }
// although in this case this is no more useful than just "public void foo(Eatable x)"

This T does not necessarily have to be defined in the class declaration. Another method may be declared like this:

public class Test{
   public <T extends Eatable> void bar(){ }
}

which has no indication of where T is coming from. This method could be called like this:

test.<EatableClass>bar();

The foo method from before can figure out T from its parameter, but this bar method needs to be told what T is.

Julia

Works with: Julia version 0.6

Julia allows user defined types with inheritance. Misuse of a type generally produces a compile time error message.

abstract type Edible end
eat(::Edible) = "Yum!"

mutable struct FoodBox{T<:Edible}
    food::Vector{T}
end

struct Carrot <: Edible
    variety::AbstractString
end

struct Brick
    volume::Float64
end

c = Carrot("Baby")
b = Brick(125.0)
eat(c)
eat(b)
Output:
MethodError: no method matching eat(::Brick)
Closest candidates are:
  eat(!Matched::Edible) at console:2

Kotlin

In the following program we define an interface, Eatable, and two classes - Cheese and Meat - which implement it and must therefore implement its eat() method because the interface itself does not provide a default implementation.

We then define a generic class, FoodBox, whose type parameter, T, is constrained to an Eatable type and instantiate it using both the Cheese and Meat types:

// version 1.0.6

interface Eatable {
    fun eat()
}

class Cheese(val name: String) : Eatable {
    override fun eat() {
       println("Eating $name")
    }

    override fun toString() = name
}

class Meat(val name: String) : Eatable {
    override fun eat() {
       println("Eating $name")
    }

    override fun toString() = name
}

class FoodBox<T: Eatable> {
    private val foodList =  mutableListOf<T>()

    fun add(food: T) {
        foodList.add(food)
    } 

    override fun toString() = foodList.toString()   
}

fun main(args: Array<String>) {
    val cheddar =  Cheese("cheddar")
    val feta = Cheese("feta")
    val cheeseBox = FoodBox<Cheese>()
    cheeseBox.add(cheddar)
    cheeseBox.add(feta)
    println("CheeseBox contains : $cheeseBox")

    val beef = Meat("beef")
    val ham = Meat("ham")
    val meatBox = FoodBox<Meat>()
    meatBox.add(beef)
    meatBox.add(ham)
    println("MeatBox contains : $meatBox")

    cheddar.eat()
    beef.eat()
    println("Full now!")
}
Output:
CheeseBox contains : [cheddar, feta]
MeatBox contains : [beef, ham]
Eating cheddar
Eating beef
Full now!

Morfa

Translation of: D

Template Version

import morfa.type.traits;

template < T >
alias IsEdible = HasMember< T, "eat" >;

template < T >
if (IsEdible< T >)
struct FoodBox
{
    var food: T[];
}

struct Carrot 
{
    func eat(): void {}
}

struct Car {}

func main(): void 
{
    var carrotBox: FoodBox< Carrot >;   // OK
    carrotBox.food ~= Carrot();        // Adds a carrot

    // var carBox: FoodBox< Car >;      // Not allowed
    static assert( not trait(compiles, func() { var carBox: FoodBox< Car >; } ));
}


Interface Version

interface IEdible 
{ 
    public func eat(): void;
}

template < T >
if (IsDerivedOf< T, IEdible >)
struct FoodBox
{
    var food: T[];
}

class Carrot: IEdible 
{
    public override func eat(): void {}
}

class Car {}

func main(): void 
{
    var carrotBox: FoodBox< Carrot >;   // OK
    
    // var carBox: FoodBox< Car >;      // Not allowed
    static assert( not trait(compiles, func() { var carBox: FoodBox< Car >; } ));
}

Nemerle

using System.Collections.Generic;

interface IEatable
{
    Eat() : void;
}

class FoodBox[T] : IEnumerable[T]
  where T : IEatable
{
    private _foods : list[T] = [];
    
    public this() {}
    
    public this(items : IEnumerable[T])
    {
        this._foods = $[food | food in items];
    }
    
    public Add(food : T) : FoodBox[T]
    {
        FoodBox(food::_foods);
    }
    
    public GetEnumerator() : IEnumerator[T]
    {
        _foods.GetEnumerator();
    }
}

class Apple : IEatable
{
    public this() {}
    
    public Eat() : void
    {
        System.Console.WriteLine("nom..nom..nom");
    }
}

mutable appleBox = FoodBox();
repeat(3) {
    appleBox = appleBox.Add(Apple());
}

foreach (apple in appleBox) apple.Eat();
Output:
nom..nom..nom
nom..nom..nom
nom..nom..nom

Nim

type
  Eatable = concept e
    eat(e)

  FoodBox[e: Eatable] = seq[e]

  Food = object
    name: string
    count: int

proc eat(x: int) = echo "Eating the int: ", x
proc eat(x: Food) = echo "Eating ", x.count, " ", x.name, "s"

var ints = FoodBox[int](@[1,2,3,4,5])
var fs = FoodBox[Food](@[])

fs.add Food(name: "Hamburger", count: 3)
fs.add Food(name: "Cheeseburger", count: 5)

for f in fs:
  eat(f)

Objeck

All generic 'T' types associated with the FoodBox must implement the 'Eatable' interface. Generic constrains may either be an interface or a sub-classed type.

use Collection.Generic;

interface Eatable {
  method : virtual : Eat() ~ Nil;
}

class FoodBox<T : Eatable> {
  food : List<T>;
}

class Plum implements Eatable {
  method : Eat() ~ Nil {
    "Yummy Plum!"->PrintLine();
  }
}

class Genericity {
  function : Main(args : String[]) ~ Nil {
    plums : FoodBox<Plum>;
  }
}

Objective-C

Works with: Xcode version 7

Type constraints are made on the type hierarchy, so here we make Eatable a protocol, with an eat method. Types which are Eatable would have to implement the Eatable protocol and provide an eat method.

@protocol Eatable
- (void)eat;
@end

Type constraints in type parameters can be made via the : keyword, indicating in this case that the type argument must be a type that is a subtype of id<Eatable>.

@interface FoodBox<T : id<Eatable>> : NSObject
@end

OCaml

OCaml handles type constraints through modules and module types.

A module type defines a set of operations that must be implemented by a module:

module type Eatable = sig
  type t
  val eat : t -> unit
end

We just require that module instances of this module type describe a type t and implement a function eat which takes in the type and returns nothing.

The FoodBox generic type could be implemented as a functor (something which takes a module as an argument and returns another module):

module MakeFoodBox(A : Eatable) = struct
  type elt = A.t
  type t = F of elt list
  let make_box_from_list xs = F xs
end

We can create a module that is an instance of Eatable by specifying a type providing an implementation for the function eat. Here we define a module Banana, and make it an instance of Eatable.

type banana = Foo (* a dummy type *)

module Banana : Eatable with type t = banana = struct
  type t = banana
  let eat _ = print_endline "I'm eating a banana"
end

We can also create modules that use an existing type as its t. The following module uses float as its type:

module EatFloat : Eatable with type t = float = struct
  type t = float
  let eat f = Printf.printf "I'm eating %f\n%!" f
end

Then, to make a FoodBox out of one of these modules, we need to call the functor on the module that specifies the type parameter:

module BananaBox = MakeFoodBox (Banana)
module FloatBox = MakeFoodBox (EatFloat)

let my_box = BananaBox.make_box_from_list [Foo]
let your_box = FloatBox.make_box_from_list [2.3; 4.5]

Unfortunately, it is kind of cumbersome in that, for every type parameter we want to use for this generic type, we will have to explicitly create a module for the resulting type (i.e. BananaBox, FloatBox). And the operations on that resulting type (i.e. make_box_from_list) are tied to each specific module.

ooRexx

ooRexx methods, routines, and collections are all untyped, so there are no language-level checks for type matches. Tests for identity need to be performed at runtime using mechanisms such as the object isA method.

call dinnerTime "yogurt"
call dinnerTime .pizza~new
call dinnerTime .broccoli~new


-- a mixin class that defines the interface for being "food", and
-- thus expected to implement an "eat" method
::class food mixinclass object
::method eat abstract

::class pizza subclass food
::method eat
  Say "mmmmmmmm, pizza".

-- mixin classes can also be used for multiple inheritance
::class broccoli inherit food
::method eat
  Say "ugh, do I have to?".

::routine dinnerTime
  use arg dish
  -- ooRexx arguments are typeless, so tests for constrained
  -- types must be peformed at run time.  The isA method will
  -- check if an object is of the required type
  if \dish~isA(.food) then do
     say "I can't eat that!"
     return
  end
  else dish~eat
Output:
I can't eat that!
mmmmmmmm, pizza.
ugh, do I have to?.

OxygenBasic

Generic but not too generic I trust.

macro Gluttony(vartype, capacity, foodlist)
'==========================================

typedef vartype physical

enum food foodlist

type ActualFood
  sys      name
  physical size
  physical quantity
end type

Class foodbox
'============
has ActualFood Item[capacity]
sys max

method put(sys f, physical s,q)
  max++
  Item[max]<=f,s,q
end method

method GetNext(ActualFood *Stuff)
  if max then
    copy @stuff,@Item[max], sizeof Item
    max--
  end if
end method

end class

Class Gourmand
'=============
physical WeightGain, SleepTime

method eats(ActualFood *stuff)
  WeightGain+=stuff.size*stuff.quantity*0.75
  stuff.size=0
  stuff.quantity=0
end method

end class

end macro


'IMPLEMENTATION
'==============


Gluttony (
double,100,{
oyster,trout,bloater,
chocolate,truffles,
cheesecake,cream,pudding,pie
})

% small  1
% medium 2
% large  3
% huge   7

% none    0
% single  1
% few     3
% several 7
% many    12

'INSTANCE
'========

FoodBox  Hamper
Gourmand MrG

'TEST
'====

Hamper.put food.pudding,large,several
Hamper.put food.pie,huge,few
ActualFood Course
Hamper.GetNext Course
MrG.eats Course

print MrG.WeightGain 'result 15.75

Phix

Library: Phix/Class

No interfaces per se, but you can explicitly test manually for these sort of things. Needs 0.8.1+

using generic types

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()
Output:
test.exw line 9 error: not edible
foodbox contains 1 item
mmm... banana

using abstract types

With added milkshake, note that our foodbox can contain both fruit and drink!
- we would not even need to change the foodbox to be allowed to put sandwiches and biscuits in it either!
Of course you could trivially create a fruit-only foodbox just by changing the one line(ie 8) to add(fruit food).
What is much harder(/left as an exercise) is to dynamically change those kinds of restrictions at run-time.

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()
Output:
test.exw line 8: type check failure, food is {"struct","clay2",8,1}
foodbox2 contains 2 items
mmm... banana
slurp... milkshake

PicoLisp

(class +Eatable)

(dm eat> ()
   (prinl "I'm eatable") )


(class +FoodBox)
# obj

(dm set> (Obj)
   (unless (method 'eat> Obj)                # Check if the object is eatable
      (quit "Object is not eatable" Obj) )
   (=: obj Obj) )                            # If so, set the object


(let (Box (new '(+FoodBox))  Eat (new '(+Eatable))  NoEat (new '(+Bla)))
   (set> Box Eat)       # Works
   (set> Box NoEat) )   # Gives an error
Output:
$384320489 -- Object is not eatable

? (show Box)          
$384320487 (+FoodBox)
   obj $384320488

? (show Box 'obj)
$384320488 (+Eatable)

? (show NoEat)   
$384320489 (+Bla)

Racket

edible<%> objects simply need to state that they implement the interface in the second argument to class*. By doing so they will be forced to implement eat.

#lang racket
(module+ test (require tests/eli-tester))

;; This is all that an object should need to properly implement.
(define edible<%>
  (interface () [eat (->m void?)]))

(define (generic-container<%> containee/c)
  (interface ()
    [contents  (->m (listof containee/c))]
    [insert    (->m containee/c void?)]
    [remove-at (->m exact-nonnegative-integer? containee/c)]
    [count     (->m exact-nonnegative-integer?)]))

(define ((generic-box-mixin containee/c) %)
  (->i ([containee/c contract?])
       (rv (containee/c) (implementation?/c (generic-container<%> containee/c))))
  (class* % ((generic-container<%> containee/c))
    (super-new)
    (define l empty)
    (define/public (contents) l)
    (define/public (insert o) (set! l (cons o l)))
    (define/public (remove-at i)
      (begin0 (list-ref l i)
              (append (take l i) (drop l (add1 i)))))
    (define/public (count) (length l))))

;; As I understand it, a "Food Box" from the task is still a generic... i.e.
;; you will specify it down ;; to an "apple-box%" so: food-box%-generic is still
;; generic. food-box% will take any kind of food.
(define/contract (food-box-mixin T%)
  (-> (or/c (λ (i) (eq? edible<%> i)) (implementation?/c edible<%>))
   (make-mixin-contract))
  (generic-box-mixin (and/c (is-a?/c edible<%>) (is-a?/c T%))))

(module+ test
  
  (define integer-box% ((generic-box-mixin integer?) object%))
  (define integer-box  (new integer-box%))
  
  (define apple%
    (class* object% (edible<%>)
      (super-new)
      (define/public (eat)
        (displayln "nom!"))))
  
  (define banana%
    (class* object% (edible<%>)
      (super-new)
      (define/public (eat)
        (displayln "peel.. peel... nom... nom!"))))
  
  (define semolina%
    (class* object% () ; <-- empty interfaces clause
      (super-new)
      ;; you can call eat on it... but it's not explicitly (or even vaguely)
      ;; edible<%>
      (define/public (eat) (displayln "blech!"))))
  
  ;; this will take any object that is edible<%> and edible<%> (therefore all
  ;; edible<%> objects)
  (define any-food-box (new ((food-box-mixin edible<%>) object%)))
  
  ;; this will take any object that is edible and an apple<%>
  ;; (therefore only apple<%>s)
  (define apple-food-box (new ((food-box-mixin apple%) object%)))
  
  (test
   ;; Test generic boxes
   (send integer-box insert 22)
   (send integer-box insert "a string") =error> exn:fail:contract?
   
   ;; Test the food box that takes any edible<%>
   (send any-food-box insert (new apple%))
   (send any-food-box insert (new banana%))
   (send any-food-box insert (new semolina%)) =error> exn:fail:contract?
   
   ;; Test the food box that takes any apple%
   (send apple-food-box insert (new apple%))
   (send apple-food-box insert (new banana%)) =error> exn:fail:contract?
   (send apple-food-box insert (new semolina%)) =error> exn:fail:contract?
   (send apple-food-box count) => 1
   
   ;; Show that you cannot make a food-box from the non-edible<%> semolina cannot
   (implementation? semolina% edible<%>) => #f
   (new ((food-box-mixin semolina%) object%)) =error> exn:fail:contract?))

All the tests pass. Look at the tests to see what generates an exception (i.e. not allowed at runtime) and what does not.

Raku

(formerly Perl 6)

subset Eatable of Any where { .^can('eat') };

class Cake { method eat() {...} }

role FoodBox[Eatable] {
    has %.foodbox;
}

class Yummy does FoodBox[Cake] { }      # composes correctly
# class Yucky does FoodBox[Int] { }     # fails to compose

my Yummy $foodbox .= new;
say $foodbox;
Output:
Yummy.new(foodbox => {})

Ruby

class Foodbox
  def initialize (*food)
    raise ArgumentError, "food must be eadible" unless  food.all?{|f| f.respond_to?(:eat)}
    @box = food
  end
end

class Fruit
  def eat; end
end

class Apple < Fruit; end

p Foodbox.new(Fruit.new, Apple.new)
# => #<Foodbox:0x00000001420c88 @box=[#<Fruit:0x00000001420cd8>, #<Apple:0x00000001420cb0>]>

p Foodbox.new(Apple.new, "string can't eat")
# => test1.rb:3:in `initialize': food must be eadible (ArgumentError)

Rust

// This declares the "Eatable" constraint. It could contain no function.
trait Eatable {
    fn eat();
}

// This declares the generic "FoodBox" type,
// whose parameter must satisfy the "Eatable" constraint.
// The objects of this type contain a vector of eatable objects.
struct FoodBox<T: Eatable> {
    _data: Vec<T>,
}

// This implements the functions associated with the "FoodBox" type.
// This statement is not required, but here it is used
// to declare a handy "new" constructor.
impl<T: Eatable> FoodBox<T> {
    fn new() -> FoodBox<T> {
        FoodBox::<T> { _data: Vec::<T>::new() }
    }
}

// This declares a simple type.
struct Banana {}

// This makes the "Banana" type satisfy the "Eatable" constraint.
// For that, every declaration inside the declaration of "Eatable"
// must be implemented here.
impl Eatable for Banana {
    fn eat() {}
}

// This makes also the primitive "char" type satisfy the "Eatable" constraint.
impl Eatable for char {
    fn eat() {}
}

fn main() {
    // This instantiate a "FoodBox" parameterized by the "Banana" type.
    // It is allowed as "Banana" implements "Eatable".
    let _fb1 = FoodBox::<Banana>::new();

    // This instantiate a "FoodBox" parameterized by the "char" type.
    // It is allowed, as "char" implements "Eatable".
    let _fb2 = FoodBox::<char>::new();

    // This instantiate a "FoodBox" parameterized by the "bool" type.
    // It is NOT allowed, as "bool" does not implement "Eatable".
    //let _fb3 = FoodBox::<bool>::new();
}

Sather

abstract class $EDIBLE is
  eat;
end;

class FOOD < $EDIBLE is
  readonly attr name:STR;
  eat is
    #OUT + "eating " + self.name + "\n";
  end;
  create(name:STR):SAME is
    res ::= new;
    res.name := name;
    return res;
  end;
end;

class CAR is
  readonly attr name:STR;
  create(name:STR):SAME is
    res ::= new;
    res.name := name;
    return res;
  end;
end;

class FOODBOX{T < $EDIBLE} is
  private attr list:LLIST{T};
  create:SAME is
    res ::= new;
    res.list := #;
    return res;
  end;
  add(c :T) is
    self.list.insert_back(c);
  end;
  elt!:T is loop yield self.list.elt!; end; end;
end;

class MAIN is
  main is
    box  ::= #FOODBOX{FOOD}; -- ok
    box.add(#FOOD("Banana"));
    box.add(#FOOD("Amanita Muscaria"));

    box2 ::= #FOODBOX{CAR};  -- not ok
    box2.add(#CAR("Punto")); -- but compiler let it pass!

    -- eat everything
    loop box.elt!.eat; end;
  end;
end;

The GNU Sather compiler v1.2.3 let the "box2" pass, even though it shouldn't. Read e.g. this tutorial's section

Scala

Scala can constrain types in many different ways. This specific constrain, for the type to contain a particular method, can be written as this:

type Eatable = { def eat: Unit }

class FoodBox(coll: List[Eatable])

case class Fish(name: String) {
  def eat {
    println("Eating "+name)
  }
}

val foodBox = new FoodBox(List(new Fish("salmon")))

A more extensive discussion on genericity in Scala and some of the constrains that can be imposed can be found on Parametric Polymorphism.

Sidef

class FoodBox(*food { .all { .respond_to(:eat) } }) { }

class Fruit { method eat { ... } }
class Apple < Fruit {  }

say FoodBox(Fruit(), Apple()).dump  #=> FoodBox(food: [Fruit(), Apple()])
say FoodBox(Apple(), "foo")         #!> ERROR: class `FoodBox` !~ (Apple, String)

Swift

Here we make Eatable a protocol, with an eat method. Types which are Eatable would have to conform to the Eatable protocol and provide an eat method.

protocol Eatable {
    func eat()
}

Type constraints in type parameters can be made via the : syntax, indicating in this case that the type argument must be a type that is a subtype of Eatable.

struct FoodBox<T: Eatable> {
    var food: [T]
}

Similarly a generic function or method can constrain its type parameters

func foo<T: Eatable>(x: T) { }
// although in this case this is no more useful than just "func foo(x: Eatable)"

TXR

Macro wrapper for defstruct

We implement a food-box-defining macro, which checks at macro expansion time that the contained type is edible. The macro generates a structure of the specified name, which has a set-food method that additionally performs a run-time check against the exact variant of the edible type that was given to the macro.

(defmacro define-food-box (name food-type : supers . clauses)
  (unless (subtypep food-type 'edible)
    (error "~s requires edible type, not ~s" %fun% food-type))
  ^(defstruct ,name ,supers
     food
     (:method set-food (me food)
       (unless (typep food ',food-type)
         (error "~s: requires ~s object, not ~s" %fun% ',food-type food))
       (set me.food food))
     ,*clauses))

Instead of the type-based subtypep check, we could easily check for the existence of methods; e.g. test for the presence of a static slot using (static-slot-p food-type 'eat), or more specifically that it's a function: (functionp (static-slot food-type 'eat)). These tests will blow up if the macro's food-type argument isn't a struct type.

In the interactive session below, we:

  • verify that define-food-box cannot be used with a type argument that isn't derived from edible
  • define the struct type edible and then one derived from it called perishable.
  • use define-food-box to define a box called fridge which holds perishable. This works because perishable is edible
  • create an instance of fridge and show that its set-food method doesn't take an integer, or an edible; only a perishable.
Output:
$ txr -i generic.tl 
This area is under 24 hour TTY surveillance.
1> (define-food-box fridge string)
** define-food-box requires edible type, not string
** during evaluation of form (error "~s requires edible type, not ~s"
                                    'define-food-box
                                    food-type)
** ... an expansion of (error "~s requires edible type, not ~s"
                              %fun% food-type)
** which is located at generic.tl:3
1> (defstruct edible ())
#<struct-type edible>
2> (defstruct perishable (edible))
#<struct-type perishable>
3> (define-food-box fridge perishable)
#<struct-type fridge>
4> (new fridge)
#S(fridge food nil)
5> *4.(set-food 42)
** (set-food fridge): requires perishable object, not 42
** during evaluation of form (error "~s: requires ~s object, not ~s"
                                    '(set-food fridge)
                                    'perishable
                                    food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
                              %fun% 'perishable
                              food)
** which is located at expr-3:1
5> *4.(set-food (new edible))
** (set-food fridge): requires perishable object, not #S(edible)
** during evaluation of form (error "~s: requires ~s object, not ~s"
                                    '(set-food fridge)
                                    'perishable
                                    food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
                              %fun% 'perishable
                              food)
** which is located at expr-3:1
5> *4.(set-food (new perishable))
#S(perishable)
6> *4
#S(fridge food #S(perishable))

Custom defstruct clause

Wrapping defstruct is a heavy-handed approach that may be difficult to retrofit into an existing code base. One possible issue is that two developers write such a macro, and then someone needs to use both of them for the same class. But each macro wants to write its own entire defstruct form.

Here, we instead use a custom clause to inject the food slot, set-food method, and the static and dynamic checks. The mechanisms remain identical.

(define-struct-clause :food-box (food-type :form form)
  (unless (subtypep food-type 'edible)
    (compile-error form "~s requires edible type, not ~s" :food-box food-type))
  ^(food
    (:method set-food (me food)
      (unless (typep food ',food-type)
        (error "~s: requires ~s object, not ~s" %fun% ',food-type food))
      (set me.food food))))
Output:
$ txr -i generic.tl 
Apply today for a TXR credit card, and get 1MB off your next allocation.
1> (defstruct fridge ()
     (:food-box string))
** expr-1:1: defstruct: :food-box requires edible type, not string
1> (defstruct edible ())
#<struct-type edible>
2> (defstruct perishable (edible))
#<struct-type perishable>
3> (defstruct fridge ()
     (:food-box perishable))
#<struct-type fridge>
4> (new fridge)
#S(fridge food nil)
5> *4.(set-food 42)
** (set-food fridge): requires perishable object, not 42
** during evaluation of form (error "~s: requires ~s object, not ~s"
                                    '(set-food fridge)
                                    'perishable
                                    food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
                              %fun% 'perishable
                              food)
** which is located at expr-3:1
5> *4.(set-food (new edible))
** (set-food fridge): requires perishable object, not #S(edible)
** during evaluation of form (error "~s: requires ~s object, not ~s"
                                    '(set-food fridge)
                                    'perishable
                                    food)
** ... an expansion of (error "~s: requires ~s object, not ~s"
                              %fun% 'perishable
                              food)
** which is located at expr-3:1
5> *4.(set-food (new perishable))
#S(perishable)

Wren

Wren is dynamically typed and so any constraint on class instantiation can only be checked at run time.

// abstract class
class Eatable {
    eat() { /* override in child class */ }
}

class FoodBox {
    construct new(contents) {
        if (contents.any { |e| !(e is Eatable) }) {
            Fiber.abort("All FoodBox elements must be eatable.")            
        }
        _contents = contents
    }

    contents { _contents }
}

// Inherits from Eatable and overrides eat() method.
class Pie is Eatable {
    construct new(filling) { _filling = filling }

    eat() { System.print("%(_filling) pie, yum!") }
}

// Not an Eatable.
class Bicycle {
    construct new() {}
}

var items = [Pie.new("Apple"),  Pie.new("Gooseberry")]
var fb = FoodBox.new(items)
fb.contents.each { |item| item.eat() }
System.print()
items.add(Bicycle.new())
fb = FoodBox.new(items) // throws an error because Bicycle not eatable
Output:
Apple pie, yum!
Gooseberry pie, yum!

All FoodBox elements must be eatable.
[./constrained_genericity line 9] in init new(_)
[./constrained_genericity line 12] in 
[./constrained_genericity line 34] in (script)

zkl

zkl isn't statically typed so the test is done at runtime.

This is a slightly different take on the task, keeping the editables and rejecting the garbage.

class Eatable{ var v;
   fcn eat{ println("munching ",self.topdog.name); }
}
class FoodBox{
   fcn init(food1,food2,etc){
      editable,garbage:=vm.arglist.filter22("isChildOf",Eatable);
      var contents=editable;
      if(garbage) println("Rejecting: ",garbage);
   }
}
class Apple(Eatable){} class Nuts(Eatable){} class Foo{}
FoodBox(Apple,"boogers",Nuts,Foo).contents.apply2("eat");
Output:
Rejecting: L("boogers",Class(Foo))
munching Apple
munching Nuts