The answer on Confused about static dictionary in a type, in F# finished with one advice: and just in general: try to use fewer classes and more modules and functions; they're more idiomatic in F# and lead to fewer problems in general
Which is a great point, but my 30 years of OO just don't want to give up classes just yet (although I was fighting against C++ like crazy when we moved away from C...)
so let's take a practical real world object:
type Currency =
{
Ticker: string
Symbol: char
}
and MarginBracket =
{
MinSize: decimal
MaxSize: decimal
Leverage: int
InitialMargin: decimal
MaintenanceMargin: decimal
}
and Instrument =
{
Ticker: string
QuantityTickSize: int
PriceTickSize: int
BaseCurrency: Currency
QuoteCurrency: Currency
MinQuantity: decimal
MaxQuantity: decimal
MaxPriceMultiplier: decimal
MinPriceMultiplier: decimal
MarginBrackets: MarginBracket array
}
// formatting
static member private formatValueNoSign (precision: int) (value: decimal) =
let zeros = String.replicate precision "0"
String.Format($"{{0:#.%s{zeros}}}", value)
static member private formatValueSign (precision: int) (value: decimal) =
let zeros = String.replicate precision "0"
String.Format($"{{0:+#.%s{zeros};-#.%s{zeros}; 0.%s{zeros}}}", value)
member this.BaseSymbol = this.BaseCurrency.Symbol
member this.QuoteSymbol = this.QuoteCurrency.Symbol
member this.QuantityToString (quantity) = $"{this.BaseSymbol}{Instrument.formatValueSign this.QuantityTickSize quantity}"
member this.PriceToString (price) = $"{this.QuoteSymbol}{Instrument.formatValueNoSign this.PriceTickSize price}"
member this.SignedPriceToString (price) = $"{this.QuoteSymbol}{Instrument.formatValueSign this.PriceTickSize price}"
member this.RoundQuantity (quantity: decimal) = Math.Round (quantity, this.QuantityTickSize)
member this.RoundPrice (price : decimal) = Math.Round (price, this.PriceTickSize)
// price deviation allowed from instrument price
member this.LowAllowedPriceDeviation (basePrice: decimal) = this.MinPriceMultiplier * basePrice
member this.HighAllowedPriceDeviation (basePrice: decimal) = this.MaxPriceMultiplier * basePrice
module Instrument =
let private allInstruments = Dictionary<string, Instrument>()
let list () = allInstruments.Values
let register (instrument) = allInstruments.[instrument.Ticker] <- instrument
let exists (ticker: string) = allInstruments.ContainsKey (ticker.ToUpper())
let find (ticker: string) = allInstruments.[ticker.ToUpper()]
In this example, there is an Instrument object with its data and a few helper members and a module which acts as a repository when it's time to find an object by name (a trading ticker in this case, so they're known and formatted, it's not a random string)
I could move the helping member to the module, for example:
member this.LowAllowedPriceDeviation (basePrice: decimal) = this.MinPriceMultiplier * basePrice
could become:
let lowAllowedPriceDeviation basePrice instrument = instrument.MinPriceMultiplier * basePrice
So the object would become simpler and could eventually be turned into a simple storage type without any augmentations.
But I am wondering what are the practical benefits (let's just consider readability, maintainability, etc)?
Also, I don't see how this could be re-structured to not be a class, short of having an 'internal' class in the module and doing all operations through that, but that would just be shifting it.
Your intuition about turning LowAllowedPriceDeviation to a module is correct: it could become a function with the this parameter moved to the end. That is an accepted pattern.
Same goes for all other methods on the Instrument type. And the two private static methods could be come private functions in the module. The exact same approach.
The question "how this could be re-structured to not be a class" confuses me a bit, because this is not actually a class. Instrument is a record, not a class. The fact that you gave it some instance and static methods doesn't make it a class.
And finally (though, technically, this part is opinion-based), regarding "what are the practical benefits" - the answer is "composability". Functions can compose in the way that methods can't.
For example, say you wanted a way to print multiple instruments:
let printAll toString = List.iter (printfn "%s" << toString)
See how it's parametrized with a toString function? That's because I'd like to use it for printing instruments in different ways. For example, I might print their prices:
printAll priceToString (list())
But if PriceToString is a method, I'd have to introduce an anonymous function:
printAll (fun i -> i.PriceToString) (list())
This looks just a little bit more involved than using a function, but in practice it gets very complicated fast. A bigger problem, however, is that this wouldn't even compile because type inference doesn't work on properties (because it can't). In order to get it to compile, you have to add a type annotation, making it even uglier:
printAll (fun (i: Instrument) -> i.PriceToString) (list())
That's just one example of function composability, there are many others. But I'd rather not write a whole blog post on this subject, it's already much longer than I'd like.
Related
I have the type declaration
type MYVAL = INT of int
and want to perform arithmetic operations on constants and variables of type MYVAL, like
let a : MYVAL = 10
let b : MYVAL = 25
let c = a+b
However, when I run it, it claims that MYVAL does not support the operator +. Isn't MYVAL treated as an integer type? If it is not, what does INT of int do? How would you perform arithmetic operations of variables and constants of type MYVAL?
MYVAL is not treated as an integer type. If that's what you want, you can use a type abbreviation; type MYVAL = int. I'm not sure why you would want to do that, but it's definitely possible.
In your current definition, MYVAL is a single case discriminated union. It wraps a given type, but doesn't inherit any of the underlying type's operators. By the way, the way to construct a an INT is let a = INT 10, not let a : MYINT = 10.
If you want, you can implement your own addition operator, like so
type MYVAL = INT of int with
static member (+) (INT a, INT b) = INT(a+b)
which would allow you to do
let a = INT 10
let b = INT 25
let c = a+b
You would need to do this for any operator you want to use, e.g. (-), (*), etc.
This might all seem a bit confusing, I mean why wouldn't we want the operators to be generated automatically? Well, if you're writing a parser, you might want to be able to read either an int or a string. Such a parser might output a value of a type type MYVAL = INT of int | STRING of string. How would (+) be defined, then? How about (-)?
In the parser example, MYVAL would no longer be a single case discriminated union, as it has multiple cases. A natural question to ask is, why are single case discriminated unions interesting, then? Who would want to use anything like that? Turns out, it's quite neat for subtyping. Say you want to represent a number that's higher than 10. One way to do this is
type HigherThan10 = private Value of int with
static member TryCreate(x: int) =
if x >= 10
then Some(Value(x))
else None
let x = Value(1) // Error
let y = HigherThan10.TryCreate(1) // None
let z = HigherThan10.TryCreate(10) // Some
I know it's not the most interesting example, but it may be used for representing an email adress as a 'subtype' of string. Notice, by the way, how this avoids using exceptions for control flow by returning a HigerThan10 option.
The reason why a simple sum doesn't work was already explained. I'll just show another option: you could define a map2 function for your type:
type MYVAL =
| INT of int
static member map2 f (INT x) (INT y) = INT (f x y)
//This is the correct way to initialize MYVAL, since it is a single-case discriminated union
let a = INT 10
let b = INT 25
//sum
MYVAL.map2 (+) a b //INT 35
//mult
MYVAL.map2 (*) a b //INT 250
//mod
MYVAL.map2 (%) a b //INT 5
I'm adding a static builder method to a record type like this:
type ThingConfig = { url: string; token : string; } with
static member FromSettings (getSetting : (string -> string)) : ThingConfig =
{
url = getSetting "apiUrl";
token = getSetting "apiToken";
}
I can call it like this:
let config = ThingConfig.FromSettings mySettingsAccessor
Now the tricky part: I'd like to add a second overloaded builder for use from C# (ignore the duplicated implementation for now):
static member FromSettings (getSetting : System.Func<string,string>) : ThingConfig =
{
url = getSetting.Invoke "apiUrl";
token = getSetting.Invoke "apiToken";
}
This works for C#, but breaks my earlier F# call with
error FS0041: A unique overload for method 'FromSettings' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: static member ThingConfig.FromSettings : getSetting:(string -> string) -> ThingConfig, static member ThingConfig.FromSettings : getSetting:Func -> ThingConfig
Why can't F# figure out which one to call?
What would that type annotation look like? (Can I annotate the parameter type from the call site?)
Is there a better pattern for this kind of interop? (overloads accepting lambdas from both C# and F#)
Why can't F# figure out which one to call?
Overload resolution in F# is generally more limited than C#. The F# compiler will often, in the interest of safety, reject overloads that C# compiler sees as valid.
However, this specific case is a genuine ambiguity. In the interest of .NET interop, F# compiler has a special provision for lambda expressions: regularly, a lambda expression will be compiled to an F# function, but if the expected type is known to be Func<_,_>, the compiler will convert the lambda to a .NET delegate. This allows us to use .NET APIs built on higher-order functions, such as IEnumerable<_> (aka LINQ), without manually converting every single lambda.
So in your case, the compiler is genuinely confused: did you mean to keep the lambda expression as an F# function and call your F# overload, or did you mean to convert it to Func<_,_> and call the C# overload?
What would the type annotation look like?
To help the compiler out, you can explicitly state the type of the lambda expression to be string -> string, like so:
let cfg = ThingConfig.FromSettings( (fun s -> foo) : string -> string )
A slightly nicer approach would be to define the function outside of the FromSettings call:
let getSetting s = foo
let cfg = ThingConfig.FromSettings( getSetting )
This works fine, because automatic conversion to Func<_,_> only applies to lambda expressions written inline. The compiler will not convert just any function to a .NET delegate. Therefore, declaring getSetting outside of the FromSettings call makes its type unambiguously string -> string, and the overload resolution works.
EDIT: it turns out that the above no longer actually works. The current F# compiler will convert any function to a .NET delegate automatically, so even specifying the type as string -> string doesn't remove the ambiguity. Read on for other options.
Speaking of type annotations - you can choose the other overload in a similar way:
let cfg = ThingConfig.FromSettings( (fun s -> foo) : Func<_,_> )
Or using the Func constructor:
let cfg = ThingConfig.FromSettings( Func<_,_>(fun s -> foo) )
In both cases, the compiler knows that the type of the parameter is Func<_,_>, and so can choose the overload.
Is there a better pattern?
Overloads are generally bad. They, to some extent, obscure what is happening, making for programs that are harder to debug. I've lost count of bugs where C# overload resolution was picking IEnumerable instead of IQueryable, thus pulling the whole database to the .NET side.
What I usually do in these cases, I declare two methods with different names, then use CompiledNameAttribute to give them alternative names when viewed from C#. For example:
type ThingConfig = ...
[<CompiledName "FromSettingsFSharp">]
static member FromSettings (getSetting : (string -> string)) = ...
[<CompiledName "FromSettings">]
static member FromSettingsCSharp (getSetting : Func<string, string>) = ...
This way, the F# code will see two methods, FromSettings and FromSettingsCSharp, while C# code will see the same two methods, but named FromSettingsFSharp and FromSettings respectively. The intellisense experience will be a bit ugly (yet easily understandable!), but the finished code will look exactly the same in both languages.
Easier alternative: idiomatic naming
In F#, it is idiomatic to name functions with first character in the lower case. See the standard library for examples - Seq.empty, String.concat, etc. So what I would actually do in your situation, I would create two methods, one for F# named fromSettings, the other for C# named FromSettings:
type ThingConfig = ...
static member fromSettings (getSetting : string -> string) =
...
static member FromSettings (getSetting : Func<string,string>) =
ThingConfig.fromSettings getSetting.Invoke
(note also that the second method can be implemented in terms of the first one; you don't have to copy&paste the implementation)
Overload resolution is buggy in F#.
I filed already some cases, like this where it is obviously contradicting the spec.
As a workaround you can define the C# overload as an extension method:
module A =
type ThingConfig = { url: string; token : string; } with
static member FromSettings (getSetting : (string -> string)) : ThingConfig =
printfn "F#ish"
{
url = getSetting "apiUrl";
token = getSetting "apiToken";
}
module B =
open A
type ThingConfig with
static member FromSettings (getSetting : System.Func<string,string>) : ThingConfig =
printfn "C#ish"
{
url = getSetting.Invoke "apiUrl";
token = getSetting.Invoke "apiToken";
}
open A
open B
let mySettingsAccessor = fun (x:string) -> x
let mySettingsAccessorAsFunc = System.Func<_,_> (fun (x:string) -> x)
let configA = ThingConfig.FromSettings mySettingsAccessor // prints F#ish
let configB = ThingConfig.FromSettings mySettingsAccessorAsFunc // prints C#ish
Today I was just going through some basic swift concepts and was working with some examples to understand those concepts. Right now I have completed studying tuples.
I have got one doubt i.e, what is the need of using tuples ? Ya I did some digging on this here is what I got :
We can be able to return multiple values from a function. Ok but we can also do this by returning an array.
Array ok but we can return an multiple values of different types. Ok cool but this can also be done by array of AnyObject like this :
func calculateStatistics (scores:[Int])->[AnyObject]
{
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores
{
if score > max{
max = score
}
else if score < min{
min = score
}
sum += score
}
return [min,max,"Hello"]
}
let statistics = calculateStatistics([25,39,78,66,74,80])
var min = statistics[0]
var max = statistics[1]
var msg = statistics[2] // Contains hello
We can name the objects present in the tuples. Ok but I can use a dictionary of AnyObject.
I am not saying that Why to use tuples when we have got this . But there should be something only tuple can be able to do or its easy to do it only with tuples. Moreover the people who created swift wouldn't have involved tuples in swift if there wasn't a good reason. So there should have been some good reason for them to involve it.
So guys please let me know if there's any specific cases where tuples are the best bet.
Thanks in advance.
Tuples are anonymous structs that can be used in many ways, and one of them is to make returning multiple values from a function much easier.
The advantages of using a tuple instead of an array are:
multiple types can be stored in a tuple, whereas in an array you are restricted to one type only (unless you use [AnyObject])
fixed number of values: you cannot pass less or more parameters than expected, whereas in an array you can put any number of arguments
strongly typed: if parameters of different types are passed in the wrong positions, the compiler will detect that, whereas using an array that won't happen
refactoring: if the number of parameters, or their type, change, the compiler will produce a relevant compilation error, whereas with arrays that will pass unnoticed
named: it's possible to associate a name with each parameter
assignment is easier and more flexible - for example, the return value can be assigned to a tuple:
let tuple = functionReturningTuple()
or all parameters can be automatically extracted and assigned to variables
let (param1, param2, param3) = functionReturningTuple()
and it's possible to ignore some values
let (param1, _, _) = functionReturningTuple()
similarity with function parameters: when a function is called, the parameters you pass are actually a tuple. Example:
// SWIFT 2
func doSomething(number: Int, text: String) {
println("\(number): \(text)")
}
doSomething(1, "one")
// SWIFT 3
func doSomething(number: Int, text: String) {
print("\(number): \(text)")
}
doSomething(number: 1, text: "one")
(Deprecated in Swift 2) The function can also be invoked as:
let params = (1, "one")
doSomething(params)
This list is probably not exhaustive, but I think there's enough to make you favor tuples to arrays for returning multiple values
For example, consider this simple example:
enum MyType {
case A, B, C
}
func foo() -> (MyType, Int, String) {
// ...
return (.B, 42, "bar")
}
let (type, amount, desc) = foo()
Using Array, to get the same result, you have to do this:
func foo() -> [Any] {
// ...
return [MyType.B, 42, "bar"]
}
let result = foo()
let type = result[0] as MyType, amount = result[1] as Int, desc = result[2] as String
Tuple is much simpler and safer, isn't it?
Tuple is a datastructure which is lighter weight than heterogeneous Array. Though they're very similar, in accessing the elements by index, the advantage is tuples can be constructed very easily in Swift. And the intention to introduce/interpolate this(Tuple) data structure is Multiple return types. Returning multiple data from the 'callee' with minimal effort, that's the advantage of having Tuples. Hope this helps!
A tuple is ideally used to return multiple named data from a function for temporary use. If the scope of the tuple is persistent across a program you might want to model that data structure as a class or struct.
I've been trying out Swift, since it's obviously the direction that Apple wants us to go in.
However, I've been really annoyed with the fact that you can't seem to add integers of different sizes:
var a: Int64 = 1500
var b: Int32 = 12349
var c = a + b
if a < b { ... }
The yielded error is "Could not find an overload for '+' that accepts the supplied argument' — obviously since they are object types. None of the class methods seem to be of any help in up/down-converting integers.
Same situation applies with any of the type aliases, obviously, (CInt + CLong).
I can see a lot of real-world situations where it is immensely practical to be able to do integer arithmetic let alone comparisons or bitwise operations on two disparately-sized integers.
How to solve this? Explicit casting with the as operator doesn't seem to work. The Swift language book isn't much help either as it doesn't really discuss this scenario.
The Swift language book does discuss this scenario in the chapter “Numeric Type Conversion”:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values.
let a: Int64 = 1500
let b: Int32 = 12349
let c = a + Int64(b)
println("The value of c is \(c)")
The common equality/comparison members design guideline is to not implement structural equality on mutable reference types, but take a look at F# record types with mutable fields:
type Value = { mutable value: int }
let mutableRecord = { value = 1 }
let xs = Map.ofList [ mutableRecord, "abc"
{ value = 2 }, "def" ]
let abc = Map.find { value=1 } xs
mutableRecord.value <- 3
let abc = Map.find { value=3 } xs // KeyNotFoundException!
The Map is sorted internally, but mutable record fields allows me to change ordering while record instance is already inside map and this is very bad.
I think F# should infer [<NoEquality>] and [<NoComparison>] modes for F# record types that declares mutable fields, isn't it?
That's not an unreasonable stance.
There might be some clever ways to leverage this feature usefully, though I haven't thought about it deeply enough. This is basically the same thing as when you put a mutable type in a Dictionary, and you get what you deserve. (Languages can't prevent every misuse, which is why we have design guidelines and programmer judgment to fill in the gaps :) )
Anyway, there's no changing it now.