Constrained genericity: Difference between revisions

Added FreeBASIC
m (→‎{{header|TXR}}: Unbalanced code tags in bulleted section.)
(Added FreeBASIC)
 
(2 intermediate revisions by 2 users not shown)
Line 535:
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>
 
=={{header|Go}}==
Line 1,597 ⟶ 1,662:
 
=={{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.
Line 1,613 ⟶ 1,680:
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:
{{out}}
 
In the interactive session, we:
 
* verify that <code>define-food-box</code> cannot be used with a type argument that isn't derived from <code>edible</code>
Line 1,621 ⟶ 1,686:
* 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
Line 1,664 ⟶ 1,731:
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="ecmascriptwren">// abstract class
class Eatable {
eat() { /* override in child class */ }
2,122

edits