Constrained genericity: Difference between revisions

Added FreeBASIC
(Added FreeBASIC)
 
(38 intermediate revisions by 23 users not shown)
Line 19:
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:
<langsyntaxhighlight lang="ada">with Ada.Containers.Indefinite_Vectors;
 
package Nutrition is
Line 42:
subtype Food_Box is Food_Vectors.Vector;
 
end Food_Boxes;</langsyntaxhighlight>
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:
<langsyntaxhighlight lang="ada">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);
Line 51:
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.</langsyntaxhighlight>
The Tomato_Box can only contain tomatoes; the Banana_Box can only contain bananas. You can only create boxes of eatable objects.
 
Line 58:
Types which are eatable would have to implement the
<code>IEatable</code> interface and provide an <code>Eat</code> method.
<langsyntaxhighlight lang="csharp">interface IEatable
{
void Eat();
}</langsyntaxhighlight>
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>.
<langsyntaxhighlight lang="csharp">using System.Collections.Generic;
 
class FoodBox<T> where T : IEatable
{
List<T> food;
}</langsyntaxhighlight>
For example, an eatable Apple:
<langsyntaxhighlight lang="csharp">class Apple : IEatable
{
public void Eat()
Line 78:
System.Console.WriteLine("Apple has been eaten");
}
}</langsyntaxhighlight>
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.
<langsyntaxhighlight lang="csharp">using System.Collections.Generic
 
class FoodMakingBox<T> where T : IEatable, new()
Line 94:
}
}
}</langsyntaxhighlight>
 
=={{header|C++}}==
{{works with|C++11}}
Uses static assertion to disallow instantiations on incorrect types
<syntaxhighlight lang="cpp">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;
}</syntaxhighlight>
 
=={{header|Common Lisp}}==
Line 118 ⟶ 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.
<langsyntaxhighlight lang="lisp">(defclass food () ())
 
(defclass inedible-food (food) ())
Line 151 ⟶ 188:
"Return an array whose elements are declared to be of type (and
eatable food)."
(apply 'make-food-box 'eatable array-args))</langsyntaxhighlight>
 
=={{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}}==
===Template Version===
<langsyntaxhighlight lang="d">enum IsEdible(T) = is(typeof(T.eat));
 
struct FoodBox(T) if (IsEdible!T) {
Line 173 ⟶ 241:
 
//FoodBox!Car carsBox; // Not allowed
}</langsyntaxhighlight>
 
===Interface Version===
<langsyntaxhighlight lang="d">interface IEdible { void eat(); }
 
struct FoodBox(T : IEdible) {
Line 192 ⟶ 260:
FoodBox!Carrot carrotBox; // OK
//FoodBox!Car carBox; // Not allowed
}</langsyntaxhighlight>
 
=={{header|E}}==
It is surely arguable whether this constitutes an implementation
of the above task:
<langsyntaxhighlight lang="e">/** Guard accepting only objects with an 'eat' method */
def Eatable {
to coerce(specimen, ejector) {
Line 210 ⟶ 278:
def makeFoodBox() {
return [].diverge(Eatable) # A guard-constrained list
}</langsyntaxhighlight>
 
=={{header|Eiffel}}==
Line 218 ⟶ 286:
The "eatable" characteristic is modeled by a deferred class (deferred classes are similar to abstract classes in some other languages).
 
<langsyntaxhighlight lang="eiffel ">
deferred class
EATABLE
Line 229 ⟶ 297:
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>:
 
<langsyntaxhighlight lang="eiffel ">
class
APPLE
Line 248 ⟶ 316:
end
end
</syntaxhighlight>
</lang>
 
 
<langsyntaxhighlight lang="eiffel ">
class
PEAR
Line 266 ⟶ 334:
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>:
 
<langsyntaxhighlight lang="eiffel">
class
FOOD_BOX [G -> EATABLE]
Line 281 ⟶ 349:
 
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:
 
<langsyntaxhighlight lang="eiffel">
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.
Line 293 ⟶ 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:
 
<langsyntaxhighlight lang="eiffel">
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:
 
<langsyntaxhighlight lang="eiffel ">
class
APPLICATION
Line 334 ⟶ 402:
-- A pear
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:
 
<langsyntaxhighlight lang="eiffel">
-- 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.
Line 348 ⟶ 416:
including inheritance relationships and interface implementation.
But for this task, the natural choice is an explicit member constraint.
<langsyntaxhighlight lang="fsharp">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
Line 358 ⟶ 426:
 
// an instance of a Banana FoodBox
let someBananas = FoodBox [Banana(); Banana()]</langsyntaxhighlight>
 
=={{header|Forth}}==
{{works with|Forth}}
Works with any ANS Forth with one dependency
 
Needs the FMS-SI (single inheritance) library code located here:
http://soton.mpeforth.com/flag/fms/index.html
<langsyntaxhighlight lang="forth">include FMS-SI.f
include FMS-SILib.f
 
\ This code uses an implementation dependent word dfa>xt
\ which converts a data-field address to an executable token.
 
: dfa>xt ( a-addr -- xt ) \ implementation dependent for VFX Forth
5 - ;
 
: (where) { class-xt where-xt -- flag }
begin
class-xt ['] object <>
while
class-xt where-xt = if true exit then
class-xt >body sfa @ dfa>xt to class-xt
repeat false ;
 
: where ( class-xt "classname" -- flag )
' state @
if postpone literal postpone (where)
else (where)
then ; immediate
 
:class Eatable
:m eat cr ." successful eat " ;m
;class
 
\ FoodBox is defined without usinginspecting eatfor inthe anyeat way.message
:class FoodBox
object-list eatable-types
:m fillinit: { n classeatable-xttypes --init: };m
:m add: ( obj -- )
class-xt where Eatable
dup is-kindOf Eatable
if n 0 do class-xt eatable-types xtadd: loop
elseif ." not an eatable-types type " add:
else drop ." not an eatable type "
then ;m
:m test
:m get ( -- obj ) eatable-types ;m
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
: test ( obj -- )
: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:
fb get test
successful eat
successful eat
successful eat
 
FoodBox fb1
5 ' object fb1 fill: \ => not an eatable type
 
:class apple <super Eatable
;class
 
:class green-apple <superanapple apple
anapple aFoodBox add:
;class
aFoodBox test \ => successful eat successful eat
</syntaxhighlight>
 
=={{header|Fortran}}==
In Fortran all checkes are done at compile time, in particular a dummy argument has to conform class.
<syntaxhighlight lang="fortran">
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
 
</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|FreeBASIC}}==
{{trans|OxygenBasic}}
<syntaxhighlight lang="vbnet">Type physical As Double
 
Enum food
oyster = 1
trout
bloater
chocolate
truffles
cheesecake
cream
pudding
pie
End Enum
 
Type ActualFood
nombre As Integer
size As physical
quantity As physical
End Type
 
Type foodbox
Item(100) As ActualFood
max As Integer
End Type
 
Sub put_(Byref fb As foodbox, Byval f As Integer, Byval s As physical, Byval q As physical)
fb.max += 1
fb.Item(fb.max).nombre = f
fb.Item(fb.max).size = s
fb.Item(fb.max).quantity = q
End Sub
 
Sub GetNext(Byref fb As foodbox, Byref Stuff As ActualFood)
If fb.max > 0 Then
Stuff = fb.Item(fb.max)
fb.max -= 1
End If
End Sub
 
Type Gourmand
WeightGain As physical
SleepTime As physical
End Type
 
Sub eats(Byref g As Gourmand, Byref stuff As ActualFood)
g.WeightGain += stuff.size * stuff.quantity * 0.75
stuff.size = 0
stuff.quantity = 0
End Sub
 
' Test
Dim As foodbox Hamper
Dim As Gourmand MrG
Dim As ActualFood Course
 
put_(Hamper, food.pudding, 3, 7)
put_(Hamper, food.pie, 7, 3)
GetNext(Hamper, Course)
eats(MrG, Course)
 
Print MrG.WeightGain ' result 15.75
 
Sleep</syntaxhighlight>
5 ' green-apple fb1 fill:
fb1 get test
successful eat
successful eat
successful eat
successful eat
successful eat
</lang>
 
=={{header|Go}}==
Go's interfaces do exactly what this task wants.
Eatable looks like this:
<langsyntaxhighlight lang="go">type eatable interface {
eat()
}</langsyntaxhighlight>
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.
<syntaxhighlight lang ="go">type foodbox []eatable</langsyntaxhighlight>
Here is an example of an eatable type.
<langsyntaxhighlight lang="go">type peelfirst string
 
func (f peelfirst) eat() {
// peel code goes here
fmt.Println("mm, that", f, "was good!")
}</langsyntaxhighlight>
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.
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 475 ⟶ 644:
f0 := fb[0]
f0.eat()
}</langsyntaxhighlight>
{{out}}
<pre>
Line 483 ⟶ 652:
=={{header|Haskell}}==
A ''type class'' defines a set of operations that must be implemented by a type:
<langsyntaxhighlight lang="haskell">class Eatable a where
eat :: a -> String</langsyntaxhighlight>
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:
<langsyntaxhighlight lang="haskell">data (Eatable a) => FoodBox a = F [a]</langsyntaxhighlight>
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>.
<langsyntaxhighlight lang="haskell">data Banana = Foo -- the implementation doesn't really matter in this case
instance Eatable Banana where
eat _ = "I'm eating a banana"</langsyntaxhighlight>
We can declare existing types to be instances in the exact same way. The following makes <tt>Double</tt> an eatable type:
<langsyntaxhighlight lang="haskell">instance Eatable Double where
eat d = "I'm eating " ++ show d</langsyntaxhighlight>
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;
<langsyntaxhighlight lang="haskell">class Food a where
munch :: a -> String</langsyntaxhighlight>
Then we can make all instances of Food eatable using <tt>munch</tt> for <tt>eat</tt> with the following instance declaration:
<langsyntaxhighlight lang="haskell">instance (Food a) => Eatable a where
eat x = munch x</langsyntaxhighlight>
 
==Icon and {{header|Unicon}}==
Line 510 ⟶ 679:
In Unicon, new types can be defined as classes. The solution shown
follows the Scala approach.
<langsyntaxhighlight lang="unicon">import Utils # From the UniLib package to get the Class class.
 
class Eatable:Class()
Line 532 ⟶ 701:
if FoodBox([Fish("salmon")]) then write("Edible") else write("Inedible")
if FoodBox([Rock("granite")]) then write("Edible") else write("Inedible")
end</langsyntaxhighlight>
 
Sample run:
Line 543 ⟶ 712:
 
=={{header|J}}==
Implementation:
J is not a statically typed language,
<syntaxhighlight lang="j">coclass'Connoisseur'
but I do not see why we should not implement this in J:
<lang j>coclass'Connoisseur'
isEdible=:3 :0
0<nc<'eat__y'
Line 552 ⟶ 720:
coclass'FoodBox'
create=:3 :0
assert isEdible_Connoisseur_ type=:y
collection=: 0#y
)
add=:3 :0"0
'inedible' assert type e. copathisEdible_Connoisseur_ y
collection=: collection, y
EMPTY
)</lang>
)</syntaxhighlight>
An edible type would be a class that has a verb with the name 'eat'. For example:
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>).
<lang j>coclass'Apple'
 
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:
<syntaxhighlight lang="j">coclass'Apple'
eat=:3 :0
smoutput'delicious'
)</langsyntaxhighlight>
And here is a quicky demo of the above:
<syntaxhighlight lang="j">
<lang j>
lunch=:(<'Apple') conew 'FoodBox'
a1=: conew 'Apple'
a2=: conew 'Apple'
Line 573 ⟶ 745:
george=: conew 'Connoisseur'
add__lunch george
|inedible: assert</langsyntaxhighlight>
 
=={{header|Java}}==
Line 580 ⟶ 752:
Types which are Eatable would have to implement the
<code>Eatable</code> interface and provide an <code>eat</code> method.
<langsyntaxhighlight lang="java5">interface Eatable
{
void eat();
}</langsyntaxhighlight>
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>.
<langsyntaxhighlight lang="java5">import java.util.List;
 
class FoodBox<T extends Eatable>
{
public List<T> food;
}</langsyntaxhighlight>
Similarly a generic method can constrain its type parameters
<langsyntaxhighlight 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)"</langsyntaxhighlight>
This <code>T</code> does not necessarily have to be defined in the class declaration. Another method may be declared like this:
<langsyntaxhighlight lang="java5">public class Test{
public <T extends Eatable> void bar(){ }
}</langsyntaxhighlight>
which has no indication of where <code>T</code> is coming from. This method could be called like this:
<syntaxhighlight lang ="java5">test.<EatableClass>bar();</langsyntaxhighlight>
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}}==
{{trans|D}}
===Template Version===
<syntaxhighlight lang="morfa">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 >; } ));
}</syntaxhighlight>
 
 
===Interface Version===
 
<syntaxhighlight lang="morfa">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 >; } ));
}</syntaxhighlight>
 
=={{header|Nemerle}}==
<langsyntaxhighlight Nemerlelang="nemerle">using System.Collections.Generic;
 
interface IEatable
Line 648 ⟶ 974:
}
 
foreach (apple in appleBox) apple.Eat();</langsyntaxhighlight>
{{out}}
<pre>nom..nom..nom
Line 655 ⟶ 981:
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">type
Eatable = genericconcept e
eat(e)
 
Line 675 ⟶ 1,001:
 
for f in fs:
eat(f)</langsyntaxhighlight>
 
=={{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}}==
{{works with|Xcode|7}}
Type constraints are made on the type hierarchy, so here we make <code>Eatable</code> a protocol, with an <code>eat</code> method.
Types which are Eatable would have to implement the
<code>Eatable</code> protocol and provide an <code>eat</code> method.
<syntaxhighlight lang="objc">@protocol Eatable
- (void)eat;
@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>.
<syntaxhighlight lang="objc">@interface FoodBox<T : id<Eatable>> : NSObject
@end</syntaxhighlight>
 
=={{header|OCaml}}==
Line 681 ⟶ 1,043:
 
A module type defines a set of operations that must be implemented by a module:
<langsyntaxhighlight lang="ocaml">module type Eatable = sig
type t
val eat : t -> unit
end</langsyntaxhighlight>
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''
(something which takes a module as an argument and returns another module):
<langsyntaxhighlight lang="ocaml">module MakeFoodBox(A : Eatable) = struct
type elt = A.t
type t = F of elt list
let make_box_from_list xs = F xs
end</langsyntaxhighlight>
 
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>.
<langsyntaxhighlight lang="ocaml">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</langsyntaxhighlight>
 
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:
<langsyntaxhighlight lang="ocaml">module EatFloat : Eatable with type t = float = struct
type t = float
let eat f = Printf.printf "I'm eating %f\n%!" f
end</langsyntaxhighlight>
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:
<langsyntaxhighlight lang="ocaml">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]</langsyntaxhighlight>
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
Line 725 ⟶ 1,087:
Tests for identity need to be performed at runtime using mechanisms
such as the object isA method.
<syntaxhighlight lang="oorexx">call dinnerTime "yogurt"
<lang ooRexx>
call dinnerTime "yogurt"
call dinnerTime .pizza~new
call dinnerTime .broccoli~new
Line 754 ⟶ 1,115:
return
end
else dish~eat</syntaxhighlight>
{{out}}
</lang>
<pre>I can't eat that!
 
mmmmmmmm, pizza.
ugh, do I have to?.</pre>
 
=={{header|OxygenBasic}}==
Generic but not too generic I trust.
<langsyntaxhighlight lang="oxygenbasic">
macro Gluttony(vartype, capacity, foodlist)
'==========================================
Line 846 ⟶ 1,209:
 
print MrG.WeightGain 'result 15.75
</syntaxhighlight>
</lang>
 
=={{header|Perl 6Phix}}==
{{libheader|Phix/Class}}
{{works with|Rakudo|2010.09.17}}
No interfaces per se, but you can explicitly test manually for these sort of things.
<lang perl6>subset Eatable of Any where { .^can('eat') };
Needs 0.8.1+
=== using generic types ===
<syntaxhighlight lang="phix">include builtins\structs.e as structs
 
class foodbox
class Cake { method 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
role FoodBox[Eatable ::T] {
hasstring T %.foodbox;name
procedure eat()
}
printf(1,"mmm... %s\n",{this.name})
end procedure
end class
fruit banana = new({"banana"})
 
class clay
class Yummy does FoodBox[Cake] { } # composes correctly
string name = "fletton"
# class Yucky does FoodBox[Int] { } # fails to compose
end class
clay brick = new()
 
lunchbox.add(banana)
my Yummy $foodbox .= new;
try
say $foodbox.perl;</lang>
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>
<lang>Yummy.new(foodbox => {})</lang>
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
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()</syntaxhighlight>
{{out}}
<pre>
test.exw line 8: type check failure, food is {"struct","clay2",8,1}
foodbox2 contains 2 items
mmm... banana
slurp... milkshake
</pre>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(class +Eatable)
 
(dm eat> ()
Line 884 ⟶ 1,362:
(let (Box (new '(+FoodBox)) Eat (new '(+Eatable)) NoEat (new '(+Bla)))
(set> Box Eat) # Works
(set> Box NoEat) ) # Gives an error</langsyntaxhighlight>
{{out}}
<pre>$384320489 -- Object is not eatable
Line 904 ⟶ 1,382:
By doing so they will be forced to implement <code>eat</code>.
 
<langsyntaxhighlight lang="racket">#lang racket
(module+ test (require tests/eli-tester))
 
Line 989 ⟶ 1,467:
;; 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?))</langsyntaxhighlight>
 
All the tests pass. Look at the tests to see what generates an exception (i.e.
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}}==
<syntaxhighlight lang="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)
</syntaxhighlight>
 
=={{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}}==
<langsyntaxhighlight lang="sather">abstract class $EDIBLE is
eat;
end;
Line 1,045 ⟶ 1,615:
loop box.elt!.eat; end;
end;
end;</langsyntaxhighlight>
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,052 ⟶ 1,622:
This specific constrain, for the type to contain a particular method,
can be written as this:
<langsyntaxhighlight lang="scala">type Eatable = { def eat: Unit }
 
class FoodBox(coll: List[Eatable])
Line 1,062 ⟶ 1,632:
}
 
val foodBox = new FoodBox(List(new Fish("salmon")))</langsyntaxhighlight>
A more extensive discussion on genericity in Scala and some of the constrains
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}}==
Line 1,070 ⟶ 1,649:
Types which are Eatable would have to conform to the <code>Eatable</code> protocol
and provide an <code>eat</code> method.
<langsyntaxhighlight lang="swift">protocol Eatable {
func eat()
}</langsyntaxhighlight>
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>.
<langsyntaxhighlight lang="swift">struct FoodBox<T: Eatable> {
var food: [T]
}</langsyntaxhighlight>
Similarly a generic function or method can constrain its type parameters
<langsyntaxhighlight lang="swift">func foo<T: Eatable>(x: T) { }
// although in this case this is no more useful than just "func foo(x: Eatable)"</langsyntaxhighlight>
 
=={{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}}==
Line 1,086 ⟶ 1,838:
 
This is a slightly different take on the task, keeping the editables and rejecting the garbage.
<langsyntaxhighlight lang="zkl">class Eatable{ var v;
fcn eat{ println("munching ",self.topdog.name); }
}
Line 1,095 ⟶ 1,847:
if(garbage) println("Rejecting: ",garbage);
}
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">class Apple(Eatable){} class Nuts(Eatable){} class Foo{}
FoodBox(Apple,"boogers",Nuts,Foo).contents.apply2("eat");</langsyntaxhighlight>
{{out}}
<pre>
Line 1,106 ⟶ 1,858:
 
<!-- 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|ARM Assembly|not statically typed}}
{{omit from|BBC BASIC}}
{{omit from|C|type system doesn't support this}}
Line 1,115 ⟶ 1,875:
{{omit from|Mathematica}}
{{omit from|Maxima}}
{{omit from|MIPS Assembly|not statically typed}}
{{omit from|Perl|not statically typed}}
{{omit from|Python|not statically typed}}
Line 1,125 ⟶ 1,886:
{{omit from|Scheme|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}}
2,122

edits