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 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()