The instance variable super cannot be accessed from the definition of another instance variable - oop

i'm trying to do some OOP in OCAML.
Here are two classes :
class virtual game_object id x y z =
object (self)
val id : int = id
val x : int = x
val y : int = y
val z : int = z
method get_x = x
method get_y = y
method get_z = z
end;;
class tile id x y z tile_type =
object(self)
inherit game_object id x y z as super
val tile_type : tile_type = tile_type
val w : int = 80
val h : int = 80
val box : Sdl.rect = Sdl.Rect.create super#get_x super#get_y w h (* This line triggers the error *)
method get_tile_type = tile_type
end
;;
When I try to compile, I get this error :
The instance variable super cannot be accessed from the definition of another instance variable
I have no idea how to solve this issue. Please help? Thank you.

The simplest solution might be to factorize the common part of the value instance, avoid the getter of the super class, and just define the rectangle from the class arguments:
class tile id x y z tile_type =
let w = 80 in
let h = 80 in
object(self)
val box = Sdl.Rect.create x y w h
inherit game_object id x y z as super
val tile_type : tile_type = tile_type
val w = w
val h = h
method get_tile_type = tile_type
end
If you need to access x and y through the getters, you could make rect mutable, initialize it to a dummy value first, and then add an initializer to set it to the correct value:
class tile id x y z tile_type =
object(self)
inherit game_object id x y z as super
val tile_type : tile_type = tile_type
val w = 80
val h = 80
val mutable box = Sdl.Rect.create 0 0 0 0
initializer box <- Sdl.Rect.create super#get_x super#get_y w h
method get_tile_type = tile_type
end

Related

Compile-time invariant/property checking in Elm

I have some value constraints/properties that I want to check at compile-time. In this example, I want to track whether a vector is normalized or not. I think I have a solution, using type tags, but I need someone with some Elm/FP experience to tell me if I have missed something obvious. Thank you.
module TagExperiment exposing (..)
type Vec t = Vec Float Float Float
type Unit = Unit
type General = General
toGeneral : Vec t -> Vec General
toGeneral (Vec x y z) =
Vec x y z
scaleBy : Vec t -> Vec t -> Vec t
scaleBy (Vec bx by bz) (Vec ax ay az) =
{- Operate on two General's or two Unit's. If you have one of each,
then the Unit needs to be cast to a General.
-}
let
mag =
sqrt ((bx * bx) + (by * by) + (bz * bz))
in
Vec (ax * mag) (ay * mag) (az * mag)
-- These cases work as desired.
a : Vec Unit
a = Vec 0 0 1
b : Vec General
b = Vec 2 2 2
d : Vec Unit
d = scaleBy a a
e : Vec General
e = scaleBy b b
g : Vec General
g = scaleBy (toGeneral a) b
h : Vec General
h = scaleBy b (toGeneral a)
-- Here is where I have trouble.
c : Vec t -- unknown... uh-oh
c = Vec 3 3 3
f : Vec t -- still unknown... sure
f = scaleBy c c
i : Vec Unit -- wrong !!!
i = scaleBy a c
j : Vec Unit -- wrong !!!
j = scaleBy c a
k : Vec General -- lucky
k = scaleBy b c
l : Vec General -- lucky
l = scaleBy c b
{- The trouble is that I am not required to specify a tag for c. I guess the
solution is to write "constructors" and make the built-in Vec constructor
opaque?
-}
newUnitVec : Float -> Float -> Float -> (Vec Unit)
newUnitVec x y z =
-- add normalization
Vec x y z
newVec : Float -> Float -> Float -> (Vec General)
newVec x y z =
Vec x y z
Yes, without Dependant Types the most ergonomic way to ensure constraints on values at compile time is to use opaque types along with a "Parse" approach.
Perhaps something like:
module Vec exposing (UnitVector, Vector, vectorToUnit)
type UnitVector
= UnitVector Float Float Float
type Vector
= Vector Float Float Float
vectorToUnit : Vector -> Maybe UnitVector
vectorToUnit (Vector x y z) =
case ( x, y, z ) of
( 0, 0, 0 ) ->
Nothing
_ ->
normalize x y z
Then, with the only ways to get a UnitVector both defined inside this module and known to obey the constraints, then any time you see a UnitVector at compile-time it is correct to assume the constraints are met.
For vectors in particular, it may be worth having a look at ianmackenzie/elm-geometry for comparison?

F# comparing lambdas for equality

I would like to try and compare F# lambdas for equality. This is, at first inspection, not possible.
let foo = 10
let la = (fun x y -> x + y + foo)
let lb = (fun x y -> x + y + foo)
printfn "lambda equals %b" (la = lb)
which generates the error
The type '('a -> 'b -> int)' does not support the 'equality' constraint because it is a function typeF# Compiler(1)
However, and surprisingly, it is possible to serialize lambda functions.
open System.Runtime.Serialization.Formatters.Binary
open System.IO
let serialize o =
let bf = BinaryFormatter()
use ms = new MemoryStream()
bf.Serialize(ms,o)
ms.ToArray()
let ByteToHex bytes =
bytes
|> Array.map (fun (x : byte) -> System.String.Format("{0:X2}", x))
|> String.concat System.String.Empty
let foo = 10
let la = (fun x y -> x + y + foo)
let lb = (fun x y -> x + y + foo)
let a = serialize la
let b = serialize lb
printfn "%s" (ByteToHex a)
printfn "%s" (ByteToHex b)
printfn "lambda equals %b" (a = b)
which suggests that if they can be serialized they can be compared. However, inspection of the byte stream for this example shows two bytes where there is a difference.
Is there possibly a strategy to solve this problem by intelligently comparing the byte arrays?
From an equivalence perspective, functions aren't meaningfully serialized.
Curryable functions in F# are implemented as derived from FSharpFunc.
let la = (fun x y -> x + y + foo)
would be implemented as an instance of the following class (in equivalent C#):
[Serializable] class Impl : FSharpFunc<int, int, int>
{
public int foo;
Impl(int foo_) => foo = foo_;
public override int Invoke(int x, int y) =>
x + y + _foo;
}
What binary serialization captures would be the full typename and the value of foo.
In fact if we look at strings in the byte stream we see:
test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Program+la#28
foo
...where la#28 is the name of our derived class.
Where the byte stream for la and lb differs is the name of the implementing class. The implementations of la and lb could be entirely different.
You could, for instance, change lb into let lb = (fun x y -> x * y + foo), and the result would be same for both runs.
You can however, do this with Code Quotations:
let foo = 10
let la = <# fun x y -> x + y + foo #>
let lb = <# fun x y -> x + y + foo #>
printfn "Is same: %b" (la.ToString() = lb.ToString()) //true
F# also supports Expression<Func<>> (C#'s expression trees) - which is also a valid avenue for comparison.

OCaml Double Semicolon Error in Toplevel

I am receiving this odd syntax error in the OCaml toplevel.
# #use "ex_8_4.ml";;
type blob = {
get : unit -> float * float;
area : unit -> float;
set : float * float -> unit;
move : float * float -> unit;
}
val new_rectangle : float -> float -> float -> float -> blob = <fun>
# let rect1 = new_rectangle 0.0 0.0 1.0 1.0 in
let rect2 = {rect1 with set = (fun _ -> ())};;
Error: Syntax error
The copying failed to include that the semicolons are underlined in the error.
It happens because the toplevel is expecting an in keyword instead of semicolons:
> let a = 1 in let b = 2;;
Error: Syntax error
One fix would be to add an in at the end:
> let a = 1 in let b = 2 in a + b;;
- : int = 3
But the simplest would be to end each let binding with semicolons:
> let a = 1;;
val a : int = 1
> let b = 2;;
val b : int = 2
> a + b;;
- : int = 3
IonuČ› G. Stan's answer is correct if what you want to define rect1 for future use, or if you don't mind that it's defined. If you wanted rect1 to be defined only for local use in defining rect2, you could use this method:
# type ints = {a : int; b : int};;
(* type ints = { a : int; b : int; } *)
# let y =
let x = {a = 1; b = 2} in
{x with b = 5};;
(* val y : ints = {a = 1; b = 5} *)
# x;;
(* Error: Unbound value x *)

Why I get sum(<P/3> <P/3>) when I use Show in OZ?

I'm learning Oz, and was trying to run an example that I found in a book, it is about to simulate a full adder, but what I get is sum( ), so I do not know where the mistake, I would appreciate your help.
Here is part of the code:
fun {XorG X Y}
fun {$ X Y}
fun {GateLoop X Y}
case X#Y of (X|Xr)#(Y|Yr) then
{X+Y-2*X*Y}|{GateLoop Xr Yr}
end
end
in
thread {GateLoop X Y} end
end
end
proc {FullAdder X Y ?C ?S}
K L M
in
K={AndG X Y}
L={AndG Y Z}
M={AndG X Z}
C={OrG K {OrG L M}}
S={XorG Z {XorG X Y}}
end
declare
X=1|1|0|_
Y=0|1|0|_ C S in
{FullAdder X Y C S}
{Show sum(C S)}
AndG and OrG are similar to XorG.
A full adder has 3 inputs and 2 outputs. Indeed you use Z in the FullAdder function but never declare it. So first add it as an argument. Then you have to define a stream for Z as you did for X and Y. Namely :
declare
X=1|1|0|_
Y=0|1|0|_
Z=1|1|1|_ C S in
{FullAdder X Y Z C S}
{Show sum(C S)}
But your main problem is that your XOR gate function is not well defined. It returns an anonymous function. So a call like {XorG A B} returns a function. A better way to implement logic gates is to use a generic function GateMaker in order not to duplicate code :
fun {GateMaker F}
fun {$ Xs Ys}
fun {GateLoop Xs Ys}
case Xs#Ys of (X|Xr)#(Y|Yr) then
{F X Y}|{GateLoop Xr Yr}
end
end
in
thread {GateLoop Xs Ys} end
end
end
Then you only have to define your gates like this :
AndG = {GateMaker fun {$ X Y} X*Y end}
OrG = {GateMaker fun {$ X Y} X+Y-X*Y end}
XorG = {GateMaker fun {$ X Y} X+Y-2*X*Y end}
...
Once you define the gates correctly your FullAdder should work properly.

How do you create an instance of a datatype with a record in SML?

For example if you were to have
datatype 'a DT =
thingy of {field1: int, field2: int}
| Empty DT;
How would you be able to create "thingy" with its fields filled in, within a function? Assuming you have the values you want for each field.
- datatype 'a DT = thingy of {x: int, y: int} | Empty;
datatype 'a DT = Empty | thingy of {x:int, y:int}
- thingy {x = 5, y = 4};
val it = thingy {x=5,y=4} : 'a DT
- fun f x y = thingy {x = x, y = y};
val f = fn : int -> int -> 'a DT