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.

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
 