This commit is contained in:
Ingy döt Net 2013-04-10 16:57:12 -07:00
parent 518da4a923
commit 764da6cbbb
6144 changed files with 83610 additions and 11 deletions

View file

@ -0,0 +1,4 @@
{{omit from|BBC BASIC}}
'''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 <tt>eat</tt> on it. Write a generic type <tt>FoodBox</tt> 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.

View file

@ -0,0 +1,4 @@
---
category:
- Type System
note: Object oriented

View file

@ -0,0 +1,24 @@
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;

View file

@ -0,0 +1,8 @@
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.

View file

@ -0,0 +1,34 @@
(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))

View file

@ -0,0 +1,21 @@
template IsEdible(T) {
enum IsEdible = 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
}

View file

@ -0,0 +1,17 @@
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
}

View file

@ -0,0 +1,14 @@
/** 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
}

View file

@ -0,0 +1,10 @@
deferred class
EATABLE
feature -- Basic operations
eat
-- Eat this eatable substance
deferred
end
end

View file

@ -0,0 +1,14 @@
class
APPLE
inherit
EATABLE
feature -- Basic operations
eat
-- Consume
do
print ("One apple eaten%N")
end
end

View file

@ -0,0 +1,14 @@
class
PEAR
inherit
EATABLE
feature -- Basic operations
eat
-- Consume
do
print ("One pear eaten%N")
end
end

View file

@ -0,0 +1,10 @@
class
FOOD_BOX [G -> EATABLE]
inherit
ARRAYED_LIST [G]
create
make
end

View file

@ -0,0 +1 @@
my_apple_box: FOOD_BOX [APPLE]

View file

@ -0,0 +1 @@
my_refrigerator: FOOD_BOX [EATABLE]

View file

@ -0,0 +1,34 @@
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

View file

@ -0,0 +1 @@
-- my_apple_box.extend (one_pear)

View file

@ -0,0 +1,3 @@
type eatable interface {
eat()
}

View file

@ -0,0 +1 @@
type foodbox []eatable

View file

@ -0,0 +1,6 @@
type peelfirst string
func (f peelfirst) eat() {
// peel code goes here
fmt.Println("mm, that", f, "was good!")
}

View file

@ -0,0 +1,22 @@
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()
}

View file

@ -0,0 +1,2 @@
class Eatable a where
eat :: a -> String

View file

@ -0,0 +1 @@
data (Eatable a) => FoodBox a = F [a]

View file

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

View file

@ -0,0 +1,2 @@
instance Eatable Double where
eat d = "I'm eating " ++ show d

View file

@ -0,0 +1,2 @@
class Food a where
munch :: a -> String

View file

@ -0,0 +1,2 @@
instance (Food a) => Eatable a where
eat x = munch x

View file

@ -0,0 +1,4 @@
interface Eatable
{
void eat();
}

View file

@ -0,0 +1,6 @@
import java.util.List;
class FoodBox<T extends Eatable>
{
public List<T> food;
}

View file

@ -0,0 +1,2 @@
public <T extends Eatable> void foo(T x) { }
// although in this case this is no more useful than just "public void foo(Eatable x)"

View file

@ -0,0 +1,3 @@
public class Test{
public <T extends Eatable> void bar(){ }
}

View file

@ -0,0 +1 @@
test.<EatableClass>bar();

View file

@ -0,0 +1,18 @@
(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

View file

@ -0,0 +1,51 @@
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;

View file

@ -0,0 +1,11 @@
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")))