Constrained genericity: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) (Rename Perl 6 -> Raku, alphabetize, minor clean-up) |
|||
Line 53: | Line 53: | ||
-- We have declared Banana and Tomato as a Food.</lang> |
-- We have declared Banana and Tomato as a Food.</lang> |
||
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++}}== |
|||
{{works with|C++11}} |
|||
Uses static assertion to disallow instantiations on incorrect types |
|||
<lang c++> |
|||
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; |
|||
}</lang> |
|||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
Line 132: | Line 94: | ||
} |
} |
||
} |
} |
||
}</lang> |
|||
=={{header|C++}}== |
|||
{{works with|C++11}} |
|||
Uses static assertion to disallow instantiations on incorrect types |
|||
<lang c++> |
|||
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; |
|||
}</lang> |
}</lang> |
||
Line 915: | Line 915: | ||
nom..nom..nom |
nom..nom..nom |
||
nom..nom..nom</pre> |
nom..nom..nom</pre> |
||
=={{header|Nim}}== |
|||
<lang 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)</lang> |
|||
=={{header|Objeck}}== |
=={{header|Objeck}}== |
||
Line 939: | Line 962: | ||
} |
} |
||
}</lang> |
}</lang> |
||
=={{header|Nim}}== |
|||
<lang 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)</lang> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
Line 1,147: | Line 1,146: | ||
print MrG.WeightGain 'result 15.75 |
print MrG.WeightGain 'result 15.75 |
||
</lang> |
</lang> |
||
=={{header|Perl 6}}== |
|||
{{works with|Rakudo|2016.01}} |
|||
<lang perl6>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.perl;</lang> |
|||
{{out}} |
|||
<lang>Yummy.new(foodbox => {})</lang> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 1,426: | Line 1,406: | ||
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) |
|||
{{works with|Rakudo|2016.01}} |
|||
<lang perl6>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.perl;</lang> |
|||
{{out}} |
|||
<lang>Yummy.new(foodbox => {})</lang> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |