If I want to create a "singleton" struct, I can do the following:
foo := struct{
bar func(string, int, bool) error
}{ bar: func(a string, b int, c bool) error {
// ...
}}
as you can see I have to write bar's signature twice. Is there a shorter way to write this?
There isn't a shorter way.
If the struct really has only one field, you may want to change foo's type:
foo := func(a string, b int, c bool) error {
// ...
}
Related
I have the following code (Playground):
// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
x % 2 == 0
}
fn bar(x: u32) -> bool {
x == 27
}
fn call_both<F>(a: F, b: F)
where
F: Fn(u32) -> bool,
{
a(5);
b(5);
}
fn main() {
call_both(foo, bar); // <-- error
}
To me, it seems like this should compile as foo and bar have the same signature: fn(u32) -> bool. Yet, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:20:20
|
20 | call_both(foo, bar);
| ^^^ expected fn item, found a different fn item
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool {bar}`
The same error can be triggered with this code:
let mut x = foo;
x = bar; // <-- error
I also tried to cast bar to the function pointer type again:
let mut x = foo;
x = bar as fn(u32) -> bool; // <-- error
This resulted in a slightly different error:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | x = bar as fn(u32) -> bool;
| ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool`
I don't understand these errors at all. What are fn items vs. fn pointers and why are foo and bar different fn items?
Function item vs. function pointer
When you refer to a function by its name, the type you get is not a function pointer (e.g. fn(u32) -> bool). Instead, you get an a zero-sized value of the function's item type (e.g. fn(u32) -> bool {foo}).
The value is zero-sized because it doesn't store the actual function pointer. The type perfectly identifies the function, so there is no need to store actual data in the type. This has several advantages, mostly about easier optimizations. A function pointer is like you would expect from other languages: it stores an address to the function.
A function pointer refers to the function via stored address; a function item refers to the function via type information.
A function item can be coerced to a function pointer in many situations, for example: as argument to a function and in let _: fn(u32) -> bool = foo; statements. Additionally, you can explicitly cast a function item to a function pointer: foo as fn(u32) -> bool.
You can read more about this topic in the reference on function items, function pointers and coercion.
Solution to your problem
In your case, the compiler isn't smart enough to figure out that you want the function pointers from your foo and bar instead of function items. When you call call_both(foo, bar) the compiler sets the generic type F to be fn(u32) -> bool {foo}, because that's the type of the first argument. And then it complains that the second argument doesn't have the same type.
You can fix that by explicitly specifying the F parameter:
call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar); // <-- even this works
After specifying the type, the compiler can correctly coerce the arguments to a function pointer. You could also as-cast the first argument to fn(u32) -> bool explicitly.
You can fix your second example by explicitly stating the function pointer type, too:
let mut x: fn(u32) -> bool = foo;
x = bar;
In general: specifying the function pointer type somewhere to trigger the coercion will work.
Each named function has a distinct type since Rust PR #19891 was merged. You can, however, cast the functions to the corresponding function pointer type with the as operator.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
It's also valid to cast only the first of the functions: the cast will be inferred on the second, because both functions must have the same type.
call_both(foo as fn(u32) -> bool, bar);
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 = ()
I have the following code (Playground):
// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
x % 2 == 0
}
fn bar(x: u32) -> bool {
x == 27
}
fn call_both<F>(a: F, b: F)
where
F: Fn(u32) -> bool,
{
a(5);
b(5);
}
fn main() {
call_both(foo, bar); // <-- error
}
To me, it seems like this should compile as foo and bar have the same signature: fn(u32) -> bool. Yet, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:20:20
|
20 | call_both(foo, bar);
| ^^^ expected fn item, found a different fn item
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool {bar}`
The same error can be triggered with this code:
let mut x = foo;
x = bar; // <-- error
I also tried to cast bar to the function pointer type again:
let mut x = foo;
x = bar as fn(u32) -> bool; // <-- error
This resulted in a slightly different error:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | x = bar as fn(u32) -> bool;
| ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool`
I don't understand these errors at all. What are fn items vs. fn pointers and why are foo and bar different fn items?
Function item vs. function pointer
When you refer to a function by its name, the type you get is not a function pointer (e.g. fn(u32) -> bool). Instead, you get an a zero-sized value of the function's item type (e.g. fn(u32) -> bool {foo}).
The value is zero-sized because it doesn't store the actual function pointer. The type perfectly identifies the function, so there is no need to store actual data in the type. This has several advantages, mostly about easier optimizations. A function pointer is like you would expect from other languages: it stores an address to the function.
A function pointer refers to the function via stored address; a function item refers to the function via type information.
A function item can be coerced to a function pointer in many situations, for example: as argument to a function and in let _: fn(u32) -> bool = foo; statements. Additionally, you can explicitly cast a function item to a function pointer: foo as fn(u32) -> bool.
You can read more about this topic in the reference on function items, function pointers and coercion.
Solution to your problem
In your case, the compiler isn't smart enough to figure out that you want the function pointers from your foo and bar instead of function items. When you call call_both(foo, bar) the compiler sets the generic type F to be fn(u32) -> bool {foo}, because that's the type of the first argument. And then it complains that the second argument doesn't have the same type.
You can fix that by explicitly specifying the F parameter:
call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar); // <-- even this works
After specifying the type, the compiler can correctly coerce the arguments to a function pointer. You could also as-cast the first argument to fn(u32) -> bool explicitly.
You can fix your second example by explicitly stating the function pointer type, too:
let mut x: fn(u32) -> bool = foo;
x = bar;
In general: specifying the function pointer type somewhere to trigger the coercion will work.
Each named function has a distinct type since Rust PR #19891 was merged. You can, however, cast the functions to the corresponding function pointer type with the as operator.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
It's also valid to cast only the first of the functions: the cast will be inferred on the second, because both functions must have the same type.
call_both(foo as fn(u32) -> bool, bar);
I have the following code (Playground):
// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
x % 2 == 0
}
fn bar(x: u32) -> bool {
x == 27
}
fn call_both<F>(a: F, b: F)
where
F: Fn(u32) -> bool,
{
a(5);
b(5);
}
fn main() {
call_both(foo, bar); // <-- error
}
To me, it seems like this should compile as foo and bar have the same signature: fn(u32) -> bool. Yet, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:20:20
|
20 | call_both(foo, bar);
| ^^^ expected fn item, found a different fn item
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool {bar}`
The same error can be triggered with this code:
let mut x = foo;
x = bar; // <-- error
I also tried to cast bar to the function pointer type again:
let mut x = foo;
x = bar as fn(u32) -> bool; // <-- error
This resulted in a slightly different error:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | x = bar as fn(u32) -> bool;
| ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool`
I don't understand these errors at all. What are fn items vs. fn pointers and why are foo and bar different fn items?
Function item vs. function pointer
When you refer to a function by its name, the type you get is not a function pointer (e.g. fn(u32) -> bool). Instead, you get an a zero-sized value of the function's item type (e.g. fn(u32) -> bool {foo}).
The value is zero-sized because it doesn't store the actual function pointer. The type perfectly identifies the function, so there is no need to store actual data in the type. This has several advantages, mostly about easier optimizations. A function pointer is like you would expect from other languages: it stores an address to the function.
A function pointer refers to the function via stored address; a function item refers to the function via type information.
A function item can be coerced to a function pointer in many situations, for example: as argument to a function and in let _: fn(u32) -> bool = foo; statements. Additionally, you can explicitly cast a function item to a function pointer: foo as fn(u32) -> bool.
You can read more about this topic in the reference on function items, function pointers and coercion.
Solution to your problem
In your case, the compiler isn't smart enough to figure out that you want the function pointers from your foo and bar instead of function items. When you call call_both(foo, bar) the compiler sets the generic type F to be fn(u32) -> bool {foo}, because that's the type of the first argument. And then it complains that the second argument doesn't have the same type.
You can fix that by explicitly specifying the F parameter:
call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar); // <-- even this works
After specifying the type, the compiler can correctly coerce the arguments to a function pointer. You could also as-cast the first argument to fn(u32) -> bool explicitly.
You can fix your second example by explicitly stating the function pointer type, too:
let mut x: fn(u32) -> bool = foo;
x = bar;
In general: specifying the function pointer type somewhere to trigger the coercion will work.
Each named function has a distinct type since Rust PR #19891 was merged. You can, however, cast the functions to the corresponding function pointer type with the as operator.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
It's also valid to cast only the first of the functions: the cast will be inferred on the second, because both functions must have the same type.
call_both(foo as fn(u32) -> bool, bar);
This example will be a little bare to strip out the custom xml parsing that I'm doing, but I've run into this issue:
package main
import (
"encoding/xml"
"fmt"
)
type Foo string
func main() {
var f Foo
var b string
c := xml.CharData{}
f = string(c)
b = string(c)
fmt.Println(b)
}
//prog.go:15: cannot use string(c) (type string) as type Foo in assignment
Foo is a type of string, what am I missing to convert the string representation of xml.CharData (which is valid, use it in many decoders) to a custom type which is a string?
Convert c to Foo directly.
f = Foo(c)
Playground: http://play.golang.org/p/WR7gCHm9El
Edit: This works because Foo is a string underneath. Foo is a new and distinct derived type; its base type is string. You can similarly make derived types for any existing type. Each derived type is distinct, so you get type safety. Conversions must be explicit.