I have a concept like this:
type Foo = concept x, y
x.test(y) is bool
And then a type that tries to define a method that implements the concept:
type Bar = object
s: string
proc test(x: Bar, y: string): bool =
x.s == y
And a type that has a generic field T: Foo with a constructor that receives a T: Foo:
type Baz[T: Foo] = object
f: T
proc make[T: Foo](f: T): auto =
result = Baz[T](f: f)
When I create a new Bar and pass it to the make proc to make a new Baz, it doesn't compile:
let bar = Bar(s: "whatever")
let made = make[Bar](bar)
Error: type mismatch: got (Bar) but expected 'T'
However it compiles if I drop the y in the concept, like x.test is bool and update the test proc accordingly.
What am I doing wrong?
Change
type Foo = concept x, y
x.test(y) is bool
To
type Foo = concept x
x.test(string) is bool
In your code, it means x and y are both Foo type. If you really means that, please try this.
proc test(x: Bar, y: Bar): bool =
x.s == y.s
Related
So I have a record type with mutable field:
type mpoint = { mutable x:int ; mutable y: int };;
let apoint = { x=3 ; y=4};;
And I have a function that expects a 'ref' and does something to its contents.
For example:
let increment x = x := !x+1;;
val increment : int ref -> unit = <fun>
Is there a way to get a 'reference' from a mutable field so that I can pass it to the function. I.e. I want to do something like:
increment apoint.x;; (* increment value of the x field 'in place' *)
Error: This expression has type int but an expression was expected of type
int ref
But the above doesn't work because apoint.x returns the value of the field not its 'ref'. If this was golang or C++ maybe we could use the & operator to indicate we want the address instead of the value of the field: &apoint.x.
(How) can we do this in Ocaml?
PS: Yes, I know its probably more common to avoid using side-effects in this way. But I promise, I am doing this for a good reason in a context where it makes more sense than this simplified/contrived example might suggest.
There's no way to do exactly what you ask for. The type of a reference is very specific:
# let x = ref 3
val x : int ref = {contents = 3}
A reference is a record with one mutable field named contents. You can't really fabricate this up from an arbitrary mutable field of some other record. Even if you are willing to lie to the type system, a field of a record is not represented at all the same as a record.
You could declare your fields as actual references:
type mpoint = { x: int ref; y: int ref; }
Then there is no problem, apoint.x really is a reference. But this representation is not as efficient, i.e., it takes more memory and there are more dereferences to access the values.
If an API is designed in an imperative style it will be difficult to use in OCaml. That's how I look at it anyway. Another way to say this is that ints are small. The interface should perhaps accept an int and return a new int, rather than accepting a reference to an int and modifying it in place.
Jeffrey Scofield explained why this can't be done in ocaml from the point of the type system.
But you can also look at it from the point of the GC (garbage collector). In ocaml internally everything is either a trivial type (int, bool, char, ...) that is stored as a 31/63 bit value or a pointer to a block of memory. Each block of memory has a header that describes the contents to the GC and has some extra bits used by GC.
When you look at a reference internally it is a pointer to the block of memory containing the record with a mutable contents. Through that pointger the GC can access the header and know the block of memory is still reachable.
But lets just assume you could pass apoint.y to a function taking a reference. Then internally the pointer would point to the middle of apoint and the GC would fail when it tries to access the header of that block because it has no idea at what offset to the pointer the header is located.
Now how to work around this?
One way that was already mentioned is to use references instead of mutable. Another way would be to use a getter and setter:
# type 'a mut = (unit -> 'a) * ('a -> unit);;
type 'a mut = (unit -> 'a) * ('a -> unit)
# type mpoint = { mutable x:int ; mutable y: int };;
type mpoint = { mutable x : int; mutable y : int; }
# let mut_x p = (fun () -> p.x), (fun x -> p.x <- x);;
val mut_x : mpoint -> (unit -> int) * (int -> unit) = <fun>
# let mut_y p = (fun () -> p.y), (fun y -> p.y <- y);;
val mut_y : mpoint -> (unit -> int) * (int -> unit) = <fun>
If you only want to incr the variable you can pass an incrementer function instead of getter/setter. Or any other collection of helper functions. A getter/setter pait is just the most generic interface.
You can always copy temporarily the content of field, call the function on that, and back again:
let increment_point_x apoint =
let x = ref apoint.x in
increment x;
apoint.x <- !x
Certainly not as efficient (nor elegant) as it could, but it works.
It is impossible to do exactly what the question asks for (#JeffreyScofield explains why, so I won't repeat that). Some workarounds have been suggested.
Here is another workaround that might work if you can change the implementation of the increment function to use a 'home made' ref type. This comes very close to what was asked for.
Instead of having it take a 'built-in' reference, we can define our own type of reference. The spirit of a 'reference' is something you can set and get. So we can characterise/represent it as a combination of a get and set function.
type 'a ref = {
set: 'a -> unit;
get: unit -> 'a;
};;
type 'a ref = { set : 'a -> unit; get : unit -> 'a; }
We can define the usual ! and := operators on this type:
let (!) cell = cell.get ();;
val ( ! ) : 'a ref -> 'a = <fun>
let (:=) cell = cell.set;;
val ( := ) : 'a ref -> 'a -> unit = <fun>
The increment function's code can remain the same even its type 'looks' the same (but it is subtly 'different' as it is now using our own kind of ref instead of built-in ref).
let increment cell = cell := !cell + 1;;
val increment : int ref -> unit = <fun>
When we want a reference to a field we can now make one. For example a function to make a reference to x:
let xref pt = {
set = (fun v -> pt.x <- v);
get = (fun () -> pt.x);
};;
val xref : mpoint -> int ref = <fun>
And now we can call increment on the x field:
increment (xref apoint);;
- : unit = ()
When I try to create two objects, where the second object has a reference to the first, I get Error: invalid type: 'var Foo' in this context: 'Bar' for var:
type
Foo = object
x: int
type
Bar = object
foo: var Foo
var f = Foo(x: 10)
var b = Bar(foo: f)
https://play.nim-lang.org/#ix=3RG3
How do I get this to work?
I think you need to create a ref Object for Foo. You can see plenty of examples for this in the sources (e.g. JsonNode and JsonNodeObj here), and is documented here and here.
type
Foo = object of RootObj
x: int
FooRef = ref Foo
Bar = object
foo: FooRef
var f = FooRef(x: 10)
var b = Bar(foo: f)
f.x = 30
doAssert b.foo.x == 30
The suffix of the object is not mandatory, but the convention is to use Ref for the ref objects and Obj for value objects (naming conventions). E.g. you can write the above as:
type
Foo = ref FooObj
FooObj = object of RootObj
x: int
Bar = object
foo: Foo
var f = Foo(x: 10)
var b = Bar(foo: f)
f.x = 30
doAssert b.foo.x == 30
The var keyword isn't valid in a type declaration context. If there is a need of nested mutable objects, you just need to declare the root one with var rather than with let, but not in the type declaration.
Here's how to do that:
type
Foo = object
x: int
type
Bar = object
foo: Foo
var f = Foo(x: 10)
var b = Bar(foo: f)
b.foo.x = 123
echo b
I wanted this kind of expression in OCaml
let wrapper obj f = fun raw -> f (new obj raw)
But I get a compiler error of Unbound class obj but so what, why isn't the compiler satisfied with creating this function which just says call a function on this object which happens to take one init arg.
Pass a function that constructs the object. For a one-argument class foo you can use new foo to get that function.
let wrapper make_obj f raw = f (make_obj raw)
class foo (x) = object
method y = x + 1
end
let answer = wrapper (new foo) (fun o -> o#y) 2
Here, wrapper has a very general type that doesn't mention objects at all. If you want to make it clear that an object constructor is expected as the argument, you can restrict the type with an annotation:
let wrapper (make_obj: (_ -> < .. >)) f raw = f (make_obj raw)
One way to look at this is that an OCaml class is a type, not a value. So you can't write a function in OCaml that accepts a class as a parameter.
Here's a session:
$ ocaml
OCaml version 4.02.1
# class abc = object method m = 12 end;;
class abc : object method m : int end
# abc;;
Error: Unbound value abc
# let f (x: abc) = x#m ;;
val f : abc -> int = <fun>
# f (new abc);;
- : int = 12
As you can see, abc is a type. Not a value.
In other languages, classes are values. But not in OCaml.
I'd like to be able to compare two typedesc in a template to see if they're referencing the same type (or at least have the same type name) but am not sure how. The == operator doesn't allow this.
type
Foo = object
Bar = object
template test(a, b: expr): bool =
a == b
echo test(Foo, Foo)
echo test(Foo, Bar)
It gives me this:
Error: type mismatch: got (typedesc[Foo], typedesc[Foo])
How can this be done?
The is operator helps: http://nim-lang.org/docs/manual.html#generics-is-operator
type
Foo = object
Bar = object
template test(a, b: expr): bool =
#a is b # also true if a is subtype of b
a is b and b is a # only true if actually equal types
echo test(Foo, Foo)
echo test(Foo, Bar)
I want to achieve a system, where objects are polymorphic over their field's contents and that content can be changed. I.e. an object offers a generic way to exchange field f with value a of type a_t with a value b of type b_t for every field f.
A first attempt would be something like this:
class ['a] not_working (a : 'a) = object
val _a = a
method field_a = _a
method modify_a new_a = {< _a = new_a >}
end
This is not polymorphic enough, as the type of not_working is:
class ['a] not_working : 'a -> object ('b) val _a : 'a method field_a : 'a method modify_a : 'a -> 'b end
i.e. the modification yields an object of the same type.
My workaround is the following:
class ['fields_t] the_class (fields : 'fields_t) = object
method field_a = fields#field_a
method field_b = fields#field_b
end
let modify_field_a instance new_a = new the_class (object method field_a = new_a ; method field_b = instance#field_b end)
let modify_field_b instance new_b = new the_class (object method field_a = instance#field_a ; method field_b = new_b end)
let instance = new the_class (object method field_a = 1 ; method field_b = "foo" end)
let mod_instance = modify_field_a instance "1"
I generate a modification function for every field in the_class and this modification function updates this field and copies all others. This is quite noisy.
Is there a way to use the object copy operator or a comparable construct in a similar manner to reduce the boilerplate?
I don't think that you can do what you're after with objects, as I think that would involve a non-regular recursive type:
type 'a foo = < modify: 'b. 'b -> 'b foo >
Note the error message if you try to define that type:
Characters 4-42:
type 'a foo = < modify: 'b. 'b -> 'b foo >;;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: In the definition of foo, type 'b foo should be 'a foo
You might have better luck using records (or first-class modules):
# type ('a, 'b) foo = { a: 'a; b: 'b };;
type ('a, 'b) foo = { a : 'a; b : 'b; }
# let new_foo a b = {a; b};;
val new_foo : 'a -> 'b -> ('a, 'b) foo = <fun>
# let modify_a r new_a = { r with a = new_a };;
val modify_a : ('a, 'b) foo -> 'c -> ('c, 'b) foo = <fun>
# let modify_b r new_b = { r with b = new_b };;
val modify_b : ('a, 'b) foo -> 'c -> ('a, 'c) foo = <fun>