How to create an F# struct with a function member and a default public constructor? - struct

I need to create a struct type for passing to an external class that is not under my control. That class requires that my struct type has a public default constructor. I need it to have a function type as a member.
The following produces error FS0001: A generic construct requires that the type 'MyStruct' have a public default constructor:
[<Struct>]
type MyStruct =
val callBack: unit -> unit
new(cb: unit -> unit) = { callBack = cb }
type ExternalClass<'T when 'T : (new : unit -> 'T) and 'T : struct> () =
member val something = new 'T()
let c = new ExternalClass<MyStruct>()
This works fine if the type of the member is changed from unit -> unit to int.
I've tried using a DefaultValue attribute, which according to the docs should work fine on a function member, but this produces two errors: error FS0765: Extraneous fields have been given values and error FS0696: This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.
How can I create a suitable type to meet the external class's constraint?

The problem here is that the type unit -> unit does not have a default value. Here's a shorter repro:
[<Struct>]
type MyStruct =
val callBack: unit -> unit
let s = MyStruct()
You get an error on the last line saying: The default, zero-initializing constructor of a struct type may only be used if all the fields of the struct type admit default initialization
The type unit -> unit doesn't admit default initialization. It must have a value of function type, and there is no such thing as "default" function value.
This is how structs in .NET work: every struct always has a default constructor, and the programmer doesn't get to implement it. Instead, the runtime initializes all fields with their default values. The idea behind this is to make allocating arrays or structs very cheap: you just zero out a memory block, and voila!
So by this logic, your callBack field must be zero-outable, but it can't be, because in F# function-typed variables can't be null.
It works fine with int, because int does indeed have a default value of zero.
Now, a "good" solution would depend on what it is you're actually trying to do. But in the absence of that information, I can suggest a couple of local workarounds.
First option - make the field have type obj (so its default value would be null) and provide a safe-ish accessor that would return an option:
[<Struct>]
type MyStruct =
val private callBack: obj
member this.Callback with get() = this.callBack |> Option.ofObj |> Option.map (fun o -> o :?> (unit -> unit))
new(cb: unit -> unit) = { callBack = cb }
The Callback accessor property would then return a (unit -> unit) option, which would be Some if the function was initialized or None if it wasn't:
> MyStruct().Callback;;
val it : (unit -> unit) option = None
> MyStruct(fun() -> ()).Callback;;
val it : (unit -> unit) option = Some <fun:it#10>
Second option - wrap the callback in a nullable type:
[<AllowNullLiteral>]
type ACallback(cb : unit -> unit) =
member val Callback = cb with get
[<Struct>]
type MyStruct =
val callBack: ACallback
new(cb: unit -> unit) = { callBack = ACallback cb }
Then:
> MyStruct().callBack;;
val it : ACallback = <null>
> MyStruct(fun() -> ()).callBack;;
val it : ACallback = FSI_0006+ACallback {Callback = <fun:it#30-1>;}
This (arguably) provides a bit more type safety at the expense of an extra allocation.
Plus, there is a possibility of getting a null, but if that's a problem, you can wrap that in an option-typed accessor too:
[<Struct>]
type MyStruct =
val private callBack: ACallback
member this.Callback with get() = this.callBack |> Option.ofObj |> Option.map (fun c -> c.Callback)
new(cb: unit -> unit) = { callBack = ACallback cb }
> MyStruct().Callback;;
val it : (unit -> unit) option = None
> MyStruct(fun() -> ()).Callback;;
val it : (unit -> unit) option = Some <fun:it#38-2>

Related

how to make these functions generic, in F#?

I have these two functions:
// load from cache
let private loadFromCacheAsync filespec =
async {
let! bytes = File.ReadAllBytesAsync(filespec) |> Async.AwaitTask
let result =
use pBytes = fixed bytes
let sourceSpan = Span<byte>(NativePtr.toVoidPtr pBytes, bytes.Length)
MemoryMarshal.Cast<byte, ShortTradeData>(sourceSpan).ToArray()
return (result |> Array.map (fun x -> x.ToTradeData()))
}
// save to cache
let private saveToCacheAsync filespec (data: TradeData array) =
Directory.CreateDirectory cacheFolder |> ignore
let sizeStruct = sizeof<ShortTradeData>
let smallData = data |> Array.map ShortTradeData.FromTradeData
use ptr = fixed smallData
let nativeSpan = Span<byte>(NativePtr.toVoidPtr ptr, data.Length * sizeStruct).ToArray()
File.WriteAllBytesAsync(filespec, nativeSpan) |> Async.AwaitTask
and I'm trying to make them generic:
// load from cache
let private loadFromCacheAsync<'a> filespec =
async {
let! bytes = File.ReadAllBytesAsync(filespec) |> Async.AwaitTask
let result =
use pBytes = fixed bytes
let sourceSpan = Span<byte>(NativePtr.toVoidPtr pBytes, bytes.Length)
MemoryMarshal.Cast<byte, 'a>(sourceSpan).ToArray()
return result
}
// save to cache
let private saveToCacheAsync<'a> filespec (data: 'a array) =
Directory.CreateDirectory cacheFolder |> ignore
let sizeStruct = sizeof<'a>
use ptr = fixed data
let nativeSpan = Span<byte>(NativePtr.toVoidPtr ptr, data.Length * sizeStruct).ToArray()
File.WriteAllBytesAsync(filespec, nativeSpan) |> Async.AwaitTask
the first one fails to compile with:
"No overloads known for method Cast"
and the second one fails to compile with:
"A type parameter is missing a constraint 'when 'a: unmanaged'
so I can make the second one compile by changing the function:
let private saveToCacheAsync<'a when 'a: unmanaged> filespec (data: 'a array) =
but I assumed that "when 'a: struct" would make more sense. Upon reading the doc, it looks like unmanaged works for structs with primitive (unmanaged) types... still don't know why struct doesn't work.
But for the first function, I don't have any idea what should be done to fix it.
The full error message is:
DataCache.fs(28, 17): [FS0041] No overloads match for method 'Cast'.
Known type of argument: Span<byte>
Available overloads:
- MemoryMarshal.Cast<'TFrom,'TTo when 'TFrom: (new: unit -> 'TFrom) and 'TFrom: struct and 'TFrom :> ValueType and 'TTo: (new: unit -> 'TTo) and 'TTo: struct and 'TTo :> ValueType>(span: ReadOnlySpan<'TFrom>) : ReadOnlySpan<'TTo>
- MemoryMarshal.Cast<'TFrom,'TTo when 'TFrom: (new: unit -> 'TFrom) and 'TFrom: struct and 'TFrom :> ValueType and 'TTo: (new: unit -> 'TTo) and 'TTo: struct and 'TTo :> ValueType>(span: Span<'TFrom>) : Span<'TTo>
and if I look at the types it takes:
'TTo when 'TFrom: (new: unit -> 'TFrom)
'TFrom: struct
'TFrom :> ValueType
'TTo: (new: unit -> 'TTo)
'TTo: struct
'TTo :> ValueType
we care about TTo here:
'TTo when 'TFrom: (new: unit -> 'TFrom)
'TTo: (new: unit -> 'TTo)
'TTo: struct
'TTo :> ValueType
I still don't get it: it looks like it needs to be a struct, and can be cast as a value type (struct then?) and have an empty constructor? I don't understand the first line.
Since loadFromCacheAsync's "from" type parameter is always byte, you only need three constraints on its "to" parameter, which you've called 'a:
'a: (new: unit -> 'a)
'a: struct
'a :> System.ValueType
The last two do seem redundant, but I assume this is just an artifact of .NET's underlying requirements.
The resulting signature for loadFromCacheAsync is:
let private loadFromCacheAsync<'a when 'a: (new: unit -> 'a) and 'a: struct and 'a :> ValueType> filespec =

How can I pass subclass to proc expecting argument of parent type?

It's possible to manually convert seq[Child] to seq[Parent] but maybe there's a better option?
type
ParentRef = ref object of RootObj
a: int
ChildRef = ref object of ParentRef
b: int
let parents = #[ParentRef()]
let children = #[ChildRef()]
proc process(list: seq[ParentRef]): void = discard list
process(parents)
process(children) # <== error
Nim has a stronger type system than many, by default it only implicitly converts types according to these rules.
We can see there that a sub-class is convertible to its superclass,
but seq[type1] is only convertible to seq[type2] if type1==type2, i.e. they are identical, not subtypes.
To add another implicit conversion relationship, one defines a type-converter, either case by case:
converter seqChildToSeqParent(c:seq[ChildRef]):seq[ParentRef]= c.mapIt(it.ParentRef)
or generically for any subtype:
converter toSeqParent[T:ParentRef](x:seq[T]):seq[ParentRef]= x.mapIt(it.ParentRef)
With one of those converters defined, the compiler will convert for you automatically, and call to process(children) will compile and run.
Maybe the better option is to use a generic proc?
type
Parent = object of RootObj
a: int
Child = object of Parent
b: int
let parents = #[Parent(a: 2)]
let children = #[Child(a: 3, b: 5)]
proc process[T: Parent](list: seq[T]): void =
echo repr(list)
echo "Accessing generic attribute a: ", list[0].a
process(parents)
process(children)
In fact, if you don't add the T : Parent restriction that proc will work for anything as long as the compiler finds all the fields it wants on the type:
type
Parent = object of RootObj
a: int
Child = object of Parent
b: int
FooBar = object of RootObj
a: int
bar: string
let parents = #[Parent(a: 2)]
let children = #[Child(a: 3, b: 5)]
let foobars = #[FooBar(a: 42, bar: "Yohoo")]
proc process[T](list: seq[T]): void =
echo repr(list)
echo "Accessing generic attribute a: ", list[0].a
process(parents)
process(children)
process(foobars)

Polymorphism typing problems with OCaml objects

On 4.03.0.
I have this code, basically:
module rec First : sig
type field
type 'a target = <at_least_this_method: field; .. > as 'a
end = First
and Second : sig
class foo : object
method at_least_this_method : First.field
end
end = Second
and Third : sig
class usage :
object
method action : #Second.foo First.target -> unit
end
end = struct
class usage = object
method action (a : #Second.foo First.target) = ()
end
end
And the last line of method action fails to type with error message:
Error: Some type variables are unbound in this type:
class usage :
object method action : #Second.foo First.target -> unit end
The method action has type (#Second.foo as 'a) First.target -> unit
where 'a is unbound
I also tried something like:
class usage = object
method action = fun (type t) (b : (#Second.foo as t) First.target) -> ()
end
But that didn't type either.
I suppose that you want to write the following code:
module rec First : sig
type field
class type target = object method at_least_this_method: field end
end = First
and Third : sig
class usage :
object
method action : #First.target -> unit
end
end = struct
class usage = object
method action : 'a. (#First.target as 'a) -> unit = fun a -> ()
end
end
I'm not sure why you are using recursive modules here.
They do not work well with classes. In particular, interfaces are not propagated to classes inside the module. This is why you need to write explicitly the type of the polymorphic method action in the body of Third.
Let me add an unsuccessful trial to solve the problem.
#c is an open type and it contains a type variable implicitly to express .. part of the object type, the type error comes since this hidden type variable is not quantified.
Interesting and confusing thing is that the use of #A.foo is not rejected at the signature even the hidden variable is not explicitly quantified. The following type-checks. (From the fear against the recursive module typing, I changed your example using a functor):
module Make(A : sig
type field
type 'a target = <at_least_this_method: field; .. > as 'a
class foo : object
method at_least_this_method : field
end
end) = struct
module type S = sig
class usage : object
method action : #A.foo A.target -> unit
end
end
module type S' = sig
class usage : object
method action : 'a . (#A.foo as 'a) A.target -> unit
end
end
end
ocamlc -c -i shows that the class declaration of the signature S and S' are identical. The type variable inside #A.foo is quantified at the method level and make action a polymorphic method.
#objmagic's answer is to move this polymorphism to class level. Then what should we do if we want to keep the method polymorphic?:
class usage = object
method action : 'a . (#A.foo as 'a) A.target -> unit = assert false
end
But this does not type-check:
Error: This expression has type 'a. (#A.foo as 'a) A.target -> unit
but an expression was expected of type
'b. (#A.foo as 'b) A.target -> unit
The type variable 'c occurs inside 'c
The type error is completely cryptic. To me it is a sign of crossing a danger line of object typing. Whenever I see this kind of error messages, I naively think it is simply impossible to define a method of such a type, or it is a bug of object typing and retreat...
BTW, there is no problem to define a polymorphic record with that type:
type t = { action : 'a . (#A.foo as 'a) A.target -> unit }
let t = { action = fun _ -> assert false }
EDIT: please refer to #gariguejej's answer below for a better explanation.
I'm not an expert of type system of objects, but here are my two cents.
Change your code to:
module rec First : sig
type field
type 'a target = <at_least_this_method: field; .. > as 'a
end = First
and Second : sig
class foo : object
method at_least_this_method : First.field
end
end = Second
and Third : sig
class ['a] usage :
object
method action : 'a First.target -> unit
end
end = struct
class ['a] usage = object
method action : 'a First.target -> unit = fun a -> ()
end
end
Use ocaml -i, we can see 'a is constrained to constraint 'a = < at_least_this_method : First.field; .. >.
module rec First :
sig
type field
type 'a target = 'a constraint 'a = < at_least_this_method : field; .. >
end
and Second :
sig class foo : object method at_least_this_method : First.field end end
and Third :
sig
class ['a] usage :
object
constraint 'a = < at_least_this_method : First.field; .. >
method action : 'a First.target -> unit
end
end
Of course, you can also manually constraint 'a to <at_least_this_method: field> if you want it to be a closed object type. For example,
module rec First : sig
type field
type 'a target = <at_least_this_method: field; .. > as 'a
end = First
and Second : sig
class foo : object
method at_least_this_method : First.field
end
end = Second
and Third : sig
class ['a] usage :
object
constraint 'a = <at_least_this_method:First.field>
method action : 'a First.target -> unit
end
end = struct
class ['a] usage = object
constraint 'a = <at_least_this_method:First.field>
method action : 'a First.target -> unit = fun a -> ()
end
end
See manual Chapter 3.10

Does a struct implement all the interfaces that one of their embedded type implement?

I have this example
// embed project main.go
package main
import (
"fmt"
)
type A struct {
A1 int
A2 int
}
func (a A) Incr() int {
a.A1++
return a.A1
}
type B struct {
A
D int
}
type C interface {
Incr() int
}
func Add(c C) {
d := c.Incr()
fmt.Println(d)
}
func main() {
var s B
s.Incr() //B has Incr
Add(s)
}
Using this example i wanted to check whether B implement interface C or not. In this example Add accept s (type B) as input. B implement C.
But when i change Incr() method from original to
func (a *A) Incr() int {
a.A1++
return a.A1
}
It compiler gives the error
./main.go:35: cannot use s (type B) as type C in argument to
AddContent: B does not implement C (Incr method has pointer receiver)
So i am still confused whether a struct implement all the interface that one of their embedded type implement.
Yes, your struct implements the method set of the embedded type.
However, when you change the signature of Incr to func (a *A) Incr() int, you need a pointer for the receiver of that method. A itself doesn't implement Incr when it has a pointer receiver.
The reason the s.Incr() call works, is that the s value is addressable, and Go automatically references it for the method call. When you pass s to Add, you're attempting to convert it to a C interface, the value would no longer be addressable, and the Incr method isn't in the method set.
In this case, you can either change the embedded type to *A,
type B struct {
*A
D int
}
take the address of s at the call site
Add(&s)
or make s a pointer (*B):
s := &B{}
Add(s)
The relevent portion of the spec
Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also
includes promoted methods with receiver *T.
If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an anonymous field *T, the method sets of S and *S both include
promoted methods with receiver T or *T.
B embedded A, so method sets of B include protomoted methods with receiver A, but does not include *A

Swift - String substringWithRange - 'String' is not convertible to '()'

I am trying some simple code, which I found on natashatherobot.com.
var str = "Hello, playground"
let rangeOfHello = Range(start: str.startIndex, end: advance(str.startIndex, 5))
let helloStr = str.substringWithRange(rangeOfHello)
return helloStr
It works fine when I try it in Playgrounds:
But when I try using it in my Xcode project it gives me a compilation error:
Any ideas why this is happening?
In your function declaration you are saying that it returns a void, but you are trying to return a string, You need to add the -> String in the end of your function to match what you are trying to do
your function:
func getStringBetween(startString: String, endString: String) -> ()
shoud be:
func getStringBetween(startString: String, endString: String) -> String
You did not specify the return type of your func:
func getStringBetween(startString: String, endString: String) -> String {
The problem is the method getStringBetween(:endString:), which you defined in your extension for String.
This method does not define a return type (there's no -> Type after the parameter list). Therefore the implicit return type is Void, so your method could be written as:
func getStringBetween(startString: String, endString: String) -> Void
In Swift the type Void is equivalent to an empty tuple ().
The problem is therefore that Swift expects a return type of Void denoted by (), but you're returning a String.
This problem is easily fixed by adding the return type String to the declaration of your method:
func getStringBetween(startString: String, endString: String) -> String
Side Note:
When writing return, without a specification of what is to be returned, Swift automatically returns ().

Resources