I have an interface in F# (generated from some typescript) that looks like this:
type [<AllowNullLiteral>] AppOptions =
abstract credential: Admin.Credential.Credential option with get, set
abstract databaseAuthVariableOverride: Object option with get, set
abstract databaseURL: string option with get, set
abstract storageBucket: string option with get, set
abstract projectId: string option with get, set
I thought that the easiest way to create an instance of that type would be to create a simple object expression, but I can't get it to work. Isn't member val allowed in object expression? If not, what is the easiest way to create a simple instance of an interface with getters and setters on all properties? This is what I tried that didn't work:
let options =
{ new Admin.AppOptions with
member val credential: Admin.Credential.Credential option = None with get, set
member val databaseAuthVariableOverride: obj option = None with get, set
member val databaseURL: string option = None with get, set
member val databaseURL: string option = None with get, set
member val projectId: string option = None with get, set
}
I dont think member var is in the object expression spec only the long form properties like this are allowed:
let options =
let mutable credential = None
let mutable databaseAuthVariableOverride = None
let mutable databaseURL = None
let mutable storageBucket = None
let mutable projectId = None
{ new AppOptions with
member x.credential with get() = credential and set v = credential <- v
member x.databaseAuthVariableOverride with get() = databaseAuthVariableOverride and set v = databaseAuthVariableOverride <- v
member x.databaseURL with get() = databaseURL and set v = databaseURL <- v
member x.storageBucket with get() = storageBucket and set v = storageBucket <- v
member x.projectId with get() = projectId and set v = projectId <- v
}
Which would project C# like code by the compiler like this:
[assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: AssemblyVersion("0.0.0.0")]
[CompilationMapping(SourceConstructFlags.Module)]
public static class _
{
[Serializable]
[AllowNullLiteral]
[CompilationMapping(SourceConstructFlags.ObjectType)]
public interface AppOptions
{
override FSharpOption<object> credential
{
get;
set;
}
override FSharpOption<object> databaseAuthVariableOverride
{
get;
set;
}
override FSharpOption<string> databaseURL
{
get;
set;
}
override FSharpOption<string> storageBucket
{
get;
set;
}
override FSharpOption<string> projectId
{
get;
set;
}
}
See sharplab
A normal type is probably more succinct here:
type t() =
interface AppOptions with
member val credential = None with get, set
member val databaseAuthVariableOverride = None with get, set
member val databaseURL = None with get, set
member val storageBucket = None with get, set
member val projectId = None with get, set
Related
I have two types coming from a C# lib:
one is defined like this (only signatures):
public class CallResult<T>: CallResult
{
public CallResult([AllowNull]T data, Error? error): base(error)
public static implicit operator bool(CallResult<T> obj)
public bool GetResultOrError([MaybeNullWhen(false)] out T data, [NotNullWhen(false)] out Error? error)
public new static WebCallResult<T> CreateErrorResult(Error error)
}
and the second one derives from it:
public class WebCallResult<T>: CallResult<T>
{
public HttpStatusCode? ResponseStatusCode { get; set; }
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? ResponseHeaders { get; set; }
public WebCallResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, [AllowNull] T data, Error? error): base(data, error)
public WebCallResult(WebCallResult<T> callResult): base(callResult.Data, callResult.Error)
public static WebCallResult<T> CreateFrom<Y>(WebCallResult<Y> source) where Y : T
public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, Error error)
}
and they both come from:
public class CallResult
{
public Error? Error { get; internal set; }
public bool Success => Error == null;
public CallResult(Error? error)
public static implicit operator bool(CallResult obj)
public static WebCallResult CreateErrorResult(Error error)
}
Some api calls return a CallResult, others return a WebCallResult.
Right now I use two times the same code to handle it:
// turn a webcall result into a Result object
let processResultWeb (applyOnOk: 'a -> 'b) (result: WebCallResult<'a>) =
match result.Success with
| true -> Result.Ok (applyOnOk result.Data)
| false -> Result.Error (decodeError result.Error)
// turn a webcall result into a Result object
let processResult (applyOnOk: 'a -> 'b) (result: CallResult<'a>) =
match result.Success with
| true -> Result.Ok (applyOnOk result.Data)
| false -> Result.Error (decodeError result.Error)
Which doesn't really make sense since it's the same code and I'm only caring about the data from the base class (CallResult).
So I would like to cast both types to the base class:
let a: WebCallResult = ...
let r = a :> CallResult
but this results in a compiler error:
[FS0001] The type 'CallResult' is not compatible with the type 'WebCallResult<'a>'
how can I check the result for both types by just accessing the fields from their base class, but using the same generic type.
Edit:
the source code of the classes is here: https://pastebin.com/mrw5W7xk
The issue is that I want to go from:
WebCallResult<'a'> to CallResult<'a>
and the generic seems to be the issue.
Using your code, I'm able to cast with no problem, even with generics. Here's an example:
let foo x =
WebCallResult<_>(System.Nullable(), Array.empty, x, Error())
let a : WebCallResult<int> = foo 3
let r = a :> CallResult<_>
let b : WebCallResult<string> = foo "str"
let q = b :> CallResult<_>
I've a Union type like this:
type AccountOpenened =
{ Owner: string
AccountId: Guid
CreatedAt: DateTimeOffset
StartingBalance: decimal }
type AccountClosed = { AccountId: Guid }
type AccountEvent = AccountOpenend | AccountClosed
I also have a 3rd party library from which I can get IReadOnlyList<IEvent> whereas IEvent as this signature:
public interface IEvent {
object Data { get; }
}
The library also provides a generic class Event<T> which has this signature:
public class Event<T> : IEvent {
public T Data { get; set; }
}
What I'm trying to achieve is to map an instance of IReadOnlyList<IEvent> to an AccountEvent list using exhaustive pattern matching.
I tried something like this:
let map (input: IEvent): AccountEvent =
match input with
| :? (Event<AccountOpened>) as e ->
{ Owner = e.Data.Owner
AccountId = e.Data.AccountId
CreatedAt = e.Data.CreatedAt
StartingBalance = e.Data.StartingBalance }
| :? (Event<AccountClosed>) as e ->
{ AccountId = e.Data.AccountId }
| _ -> failwith "Unknown Event"
This doesn't work because I get this compiler error:
This expression was expected to have type 'AccountEvent' but here has type 'AccountCreation'
What am I doing wrong here?
I am trying to override a method provided by an interface/API and have to assign a new value to one of the method's argument. If I try to assign to the passed argument, it'll give an error.
override _.Emit(eventInfo:SequenceStartEventInfo, emitter:IEmitter) =
eventInfo <- SequenceStartEventInfo(eventInfo.Source)
[...]
I am looking for behavior matching the following C# code:
public override void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) {
eventInfo = new SequenceStartEventInfo(eventInfo.Source)
...
}
If I change it and try to pass by reference (eventInfo:byref<SequenceStartEventInfo>) then it'll no longer match the available overloads.
The F# language reference on parameters and methods doesn't provide any help when dealing with this specific case. What is the best way to handle this Scenario?
In C# you can assign a new value to the argument variable, but as it is not passed by reference, this won't change the variable of the caller (even though the passed object is a reference type):
public static void Main()
{
var rt = new RefType { Value = 3 };
Change(rt);
Console.WriteLine(rt.Value); // still 3
}
public class RefType {
public int Value { get; set; }
}
public static void Change(RefType notByRef){
notByRef = new RefType { Value = 42 };
}
the F# equivalent (where parameters are immutable) would be shadowing:
type RefType() =
member val Value = 0 with get, set
let Change notByRef =
let notByRef = RefType(Value = 42);
// now, `notByRef` hides the method parameter
()
let [<EntryPoint>] Main _ =
let rt = RefType(Value = 3);
Change(rt);
printfn "%i" rt.Value // still 3
0
Given the HOCON below for a consitent-hashing-poolrouter, how do I specify the hashMapping.
akka {
actor {
serializers {
wire = "Akka.Serialization.WireSerializer, Akka.Serialization.Wire"
}
serialization-bindings {
"System.Object" = wire
}
deployment {
/data-collector {
router = consistent-hashing-pool
nr-of-instances = 10
}
}
}
loggers = ["Akka.Logger.NLog.NLogLogger,Akka.Logger.NLog"]
}
Given
let config = Configuration.load()
let systemName = config.GetString("app-config.actorsystem", "my-system")
let system = System.create systemName config
let collectorRouter =
let hashMapping (msg:obj) =
match msg with
| :? Message as msg ->
match msg with
| Parse (_, req) -> req.uniqueId |> box
| _ -> "-" |> box
ConsistentHashingPool (10, ConsistentHashMapping hashMapping)
let dataCollectorProps =
{ props (dataCollector settings.collector) with
Router = Some (collectorRouter :> RouterConfig)} //(FromConfig.Instance.WithFallback collectorRouter)
let test = spawn system "data-collector" <| dataCollectorProps
Router = Some (collectorRouter :> RouterConfig) work
Router = Some (FromConfig.Instance.WithFallback collectorRouter) doesn't
What is the correct way to specify the hashMapping function?
Edit 1
The warning from the console is
Akka.Routing.ConsistentHashingRoutingLogic|Message [Message] must be handled by hashMapping, or implement [IConsistentHashable] or be wrapped in [ConsistentHashableEnvelope]
There are three ways of specifying the hash key. My favourite is to implement IConsistentHashable and return the key (based on some properties of the message) from the ConsistentHashKey property.
Example excerpt from my Consistent Hashing article (in C#; sorry I don't know F#):
public class CurrencyPriceChangeMessage : IConsistentHashable
{
public string CurrencyPair { get; }
public decimal Price { get; }
public object ConsistentHashKey
{
get
{
return this.CurrencyPair;
}
}
The hash key will be used to route messages with the same key always to the same routee.
I'm trying to convert the following C# code to F#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string nomeDocumento;
[MarshalAs(UnmanagedType.LPStr)]
public string arquivoSaida;
[MarshalAs(UnmanagedType.LPStr)]
public string tipoDado;
}
I'm doing the following:
namespace Printer
module RawPrinterHelper =
[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)>]
type DOCINFOA =
[<MarshalAs(UnmanagedType.LPStr)>]
member this.nomeDocumento
[<MarshalAs(UnmanagedType.LPStr)>]
member this.arquivoSaida
[<MarshalAs(UnmanagedType.LPStr)>]
member this.tipoDado
But I receive:
A type definition requires one or more members. Can I let these members empty?
You can use val instead of member:
[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)>]
type DOCINFOA =
[<MarshalAs(UnmanagedType.LPStr)>]
val nomeDocumento : string
[<MarshalAs(UnmanagedType.LPStr)>]
val arquivoSaida : string
[<MarshalAs(UnmanagedType.LPStr)>]
val tipoDado : string