F# interface syntax to declare a function with byref returned object (or Tuple), like Int32.TryParse - interface

I'm not able to find how to declare a function in an interface so that I have a Tuple or byref result.
I want to simulate this syntax:
let executed, value = Int32.TryParse("123")
Let's say that I have a function with 2 input parameters and I want to know if the result is successful and in case having the result (a Record type in this case). Kind of:
type Result = {reference:string; value:decimal}
type IExecutor =
abstract member DoStuff: (aa:string) * (bb:string) * (result:byref<Result>) -> bool
abstract member DoStuff: (aa:string, bb:string, result:byref<Result>) -> bool
type Executor () =
member this.DoStuff (aa:string, bb:string, result:byref<Result>):bool =
result <- {reference="ref"; value=0m}
false
let executed, result = executor.DoStuff "aa" "bb"
or
let executed, result = executor.DoStuff("aa", "bb")
I'm not able to declare DoStuff in the interface.
The second try is a copy of the Int32.TryParse signature I see from intellisense, why doesn't work?
What is the correct syntax for having DoStuff called as I want ?

First of all to declare an interface you use abstract members and you only apply the signature
type IExecutor =
abstract member DoStuff: string*string*outref<int>->bool
If you want to implement the interface it goes as follows
type Executor() =
interface IExecutor with
member this.DoStuff (a:string,b:string,result:outref<int>) : bool =
result <- 3
true
You can call it like this
let s = new Executor() :> IExecutor
let a,b = s.DoStuff ( "lorem" "ipsum" )
Having said that, if you're consuming this only from F# avoid outrefs use tuples:
type IExecutor =
abstract member DoStuff: string->string->bool*int
type Executor() =
interface IExecutor with
member this.DoStuff (a:string) (b:string) : bool*int =
true,3
let s = new Executor() :> IExecutor
let a,b = s.DoStuff "lorem" "ipsum"

Related

Scala method notation using def name_= not working?

whenever I try to run this simple code it says that balance is not a member of Playground.cat
I read about this notation in a book, so I am confused on why it isn’t working?
class cat(var _balance:Int) {
def balance_=(nb:Int) = _balance = nb
}
val c = new cat(5)
c.balance +=25
print(c._balance)
whenever I try to run this simple code it says that balance is not a member of Playground.cat
I read about this notation in a book, so I am confused on why it isn’t working?
The error message spells it out pretty clearly: it cannot find the member balance, in other words, you are missing the getter.
It is also spelled out pretty explicitly in section 6.15 Assignments of the Scala Language Specification [bold emphasis mine]:
6.15 Assignments
Expr1 ::= [SimpleExpr ‘.’] id ‘=’ Expr
| SimpleExpr1 ArgumentExprs ‘=’ Expr
The interpretation of an assignment to a simple variable 𝑥 = 𝑒 depends on the definition of 𝑥. If 𝑥 denotes a mutable variable, then the assignment changes the current value of 𝑥 to be the result of evaluating the expression 𝑒. The type of 𝑒 is expected to conform to the type of 𝑥. If 𝑥 is a parameterless method defined in some template, and the same template contains a setter method 𝑥_= as member, then the assignment 𝑥 = 𝑒 is interpreted as the invocation 𝑥_=(𝑒) of that setter method. Analogously, an assignment 𝑓.𝑥 = 𝑒 to a parameterless method 𝑥 is interpreted as the invocation 𝑓.𝑥_=(𝑒).
To fix it, you need to add a getter of the same name in the same template (that's the name the SLS uses for class, trait, or object):
class Cat(var _balance: Int) {
def balance = _balance
def balance_=(nb: Int) = _balance = nb
}
val c = new Cat(5)
c.balance += 25
print(c._balance)
Take a look at this snippet, please:
class cat(var _balance: Int) {
def balance_=(n: Int) = _balance = n
def balance = _balance
}
val c = new cat(5)
c.balance += 25
print(c.balance)
(https://scastie.scala-lang.org/5ZiUDYizQHSJqjR3pYugYA)
If I'm getting it right, scala also needs accessor for _balance value with the same name, as c.balance += 25 gets "expanded" by compiler into
c.balance = c.balance + 25

How to assign enum type arguement in scala

object StorageType extends Enumeration{
type Name = Value
val HTML, TEXT, SUBJECT = Value
}
def read(key:String, _type:StorageType.Value = StorageType.HTML):String = {
val accessKey = getPrefix(_type) + key
DaoFactory.getPreviewStorageDao.get(accessKey).data
}
Does this mean I can only send StorageType.HTML as argument and not StorageType.SUBJECT?
Also I am pretty new to scala so can you tell me what exactly does _type do here?
The _type parameter can be any one of the StorageType.Value instances, but if you don't put any instance into it when you call the method, then the StorageType.HTML instance will be automatically assigned.

Is there a simpler way to use interfaces in F# implicitly?

I am playing a bit with F# interfaces, by creating a simple data access class.
The interface is:
type IUserAccess =
abstract member GetUsers : (dbSchema.ServiceTypes.Users -> bool) -> dbSchema.ServiceTypes.Users seq
abstract member GetAllUsers : unit -> dbSchema.ServiceTypes.Users seq
In the class, I am calling the methods in this way:
type UserAccess() =
let db = dbSchema.GetDataContext()
interface IUserAccess with
member this.GetUsers cond =
let query = query {
for row in db.Users do
select row }
query |> Seq.where cond
member this.GetAllUsers () =
(this:>IUserAccess).GetUsers (fun _ -> true)
What I'm a bit concerned with is the way I am calling GetAllUsers function, specifically with part (this:>IUserAccess). What is the simplest way of calling methods that are implemented within the same interface?
One simple option I can think of is creating GetUsers method directly within UserAccess() class and then calling it from the interface implementation of both GetUsers and GetAllUsers, but that means a new private method implemented, which I would like to avoid. Is there another option?
I think the solution by #vcsjones is probably the best option if you want to avoid defining a separate method directly inside the class. That said, declaring a separate method is actually not that ugly. You can use local definition using let binding (which is automatically compiled as a private method) and I think it makes the code look quite nice:
type UserAccess() =
let db = dbSchema.GetDataContext()
let getUsers cond =
let query = query {
for row in db.Users do
select row }
query |> Seq.where cond
interface IUserAccess with
member this.GetUsers cond = getUsers cond
member this.GetAllUsers () = getUsers (fun _ -> true)
I generally quite like this style, because it separates all the private implementation from the part of the definition where you're defining the public exposed API.
F# always implements interfaces explicitly, so your options are pretty much as you stated, but you can avoid redundant casting by introducing a let binding:
type IUserAccess =
interface
abstract member GetUsers : (obj -> bool) -> unit
abstract member GetAllUsers : unit -> unit
end
type Foo() as self =
let userAccess = self :> IUserAccess
interface IUserAccess with
member this.GetUsers(q : (obj -> bool)) : unit =
()
member this.GetAllUsers() =
userAccess.GetUsers(fun _ -> true)
I just simplified your interface and object so I could get something compiling real quick.

Type alias for inferred type

I have a method with a complicated return type and I would like to have a function which takes the result of this method as a parameter. Is it possible to create an alias for the return type of the method? Something like typeof from C++
e.g.
object Obj {
def method(x:Int) = 1 to x
type ReturnType = ???
//possible solution if i know a parameter for which the method won't fail
val x = method(1)
type ReturnType = x.type
//another possible solution, I don't need a parameter that won't fail
//the method but i still think there is a better way
lazy val x = method(1)
type ReturnType = x.type
//I would then like to have a function which takes ReturnType as a parameter
def doit(t:ReturnType) = Unit
}
The thing is that the compiler knows the type but I don't know how to get it from him.
The only way I could think of is this:
class Return[T](f:() => T) {
type Type = T
}
def getDifficultReturnType() = 1 to 10
val Return = new Return(getDifficultReturnType)
def doIt(t:Return.Type) = {
}
I am not sure if this is what you are looking for.
To my knowledge, this is not possible. Perhaps in a future Scala version with type macros.
In any case, leaving the type away if it's non-trivial is not a good design in my opinion. I understand that you don't want to type 80 characters, but if it's crucial to preserve that type (as it sounds), it should be explicated at some point.
You can use a type alias:
object Obj {
type ReturnType = My with Very[LongAndComplicated] with Name
// explicit type ensures you really get what you want:
def method(x: Int): ReturnType = 1 to x
def doit(t: ReturnType) {}
}

Scala class members and constructor parameters name clash

Consider the following class written in Java:
class NonNegativeDouble {
private final double value;
public NonNegativeDouble(double value) {
this.value = Math.abs(value);
}
public double getValue() { return value; }
}
It defines a final field called value that is initialized in the constructor, by taking its parameter called alike and applying a function to it.
I want to write something similar to it in Scala. At first, I tried:
class NonNegativeDouble(value: Double) {
def value = Math.abs(value)
}
But the compiler complains: error: overloaded method value needs result type
Obviously the compiler thinks that the expression value inside the expression Math.abs(value) refers to the method being defined. Therefore, the method being defined is recursive, so I need to state its return type. So, the code I wrote does not do what I expected it to do: I wanted value inside Math.abs(value) to refer to the constructor parameter value, and not to the method being defined. It is as if the compiler implicitly added a this. to Math.abs(this.value).
Adding val or var (or private ... variants) to the constructor parameter doesn't seem to help.
So, my question is: can I define a property with the same name as a constructor parameter, but maybe a different value? If so, how? If not, why?
Thanks!
No, you can't. In Scala, constructor parameters are properties, so it makes no sense to redefine them.
The solution, naturally, is to use another name:
class NonNegativeDouble(initValue: Double) {
val value = Math.abs(initValue)
}
Used like this, initValue won't be part of the instances created. However, if you use it in a def or a pattern matching declaration, then it becomes a part of every instance of the class.
#Daniel C. Sobral
class NonNegativeDouble(initValue: Double) {
val value = Math.abs(initValue)
}
your code is right, but "constructor parameters are properties",this is not true.
A post from the official site said,
A parameter such as class Foo(x : Int) is turned into a field if it is
referenced in one or more methods
And Martin's reply confirms its truth:
That's all true, but it should be treated as an implementation
technique. That's why the spec is silent about it.
So normally, we can still treat primary constructor parameters as normal method parameter, but when the parameters is referenced by any of the methods, the compiler will cleverly turn it into a private field.
If any formal parameter preceded by the val, the compiler generates an getter definition automatically.if var, generates a setter additionally. see the language speification section 5.3.
That's all about primary constructor parameters.
You can consider parametric field
class NonNegativeDouble(val value: Double, private val name: String ){
if (value < 0) throw new IllegalArgumentException("value cannot be negative")
override def toString =
"NonNegativeDouble(value = %s, name = %s)" format (value, name)
}
val tom = "Tom"
val k = -2.3
val a = new NonNegativeDouble(k.abs, tom)
a: NonNegativeDouble = NonNegativeDouble(value = 2.3, name = Tom)
a.value
res13: Double = 2.3
a.name
<console>:12: error: value name in class NonNegativeDouble cannot be accessed in NonNegativeDouble
a.name
val b = new NonNegativeDouble(k, tom)
java.lang.IllegalArgumentException: value cannot be negative
...
It's defines fields and parameters with the same names "value", "name".
You can add modifiers such as private ...
In the case of case classes it should be:
case class NonNegativeDouble(private val initValue: Double) {
val value = Math.abs(initValue)
def copy(value: Double = this.value) = NonNegativeDouble(value)
}
The implementation of copy is required to prevent the sintesized version of the compiler that will bind the initValue argument.
I expect that the compiler is smart enough to not retain the «extra space» for the initValue. I haven't verified this behaviour.