It is beyond me at this point. I'm trying to create an interface that looks something like
this.
type IFetchData =
abstract FetchData: string -> seq<'a>
The above declaration is valid (and compiles) but when I go to use it I get a compile time error. This expression was expected to have type 'a but here has type "what I'm currently trying to return" i.e. seq.
My example usage however looks like the following:
type SampleFetchData() =
interface IFetchData with
member self.FetchData str =
seq {
for letter in str do
yield letter // compile error here
}
I'm not sure what I'm doing wrong. All I'd like to do is allow the interface implementer to be able to write any function that returns a generic sequence either seq<string>,seq<int>,seq<record type here>, seq<union type here>, etc.
Can someone tell me what I'm missing here?
Thanks.
If you're loading the interface implementation using Reflection, then it is going to be quite difficult to work with it. The problem is that you get an object of type obj. You know that it implements IFetchData<'T> for some 'T, but statically, you don't know for which 'T. This is a problem because you can't cast the object to any more specific type - if you tried using IFetchData<obj>, it wouldn't work because you can't cast, for example, IFetchData<int> to that type.
I would recommend using a non-generic interface, which is quite common .NET pattern:
type IFetchDataUntyped =
abstract FetchData : string -> System.Collections.IEnumerable
type IFetchData<'T> =
inherit IFetchDataUntyped
abstract FetchData : string -> seq<'T>
When you load an implementation using Reflection, you can cast the object to IFetchDataUntyped and work with it in a fairly reasonable way (using Seq.cast to convert the sequence to a more specific type if you know the element type).
Depending on your application, you may also just make the FetchData method a generic method and keep the interface non-generic. Then you could cast dynamically loaded objects to the interface and invoke the method. However, this changes the design (because the method has to work for any type it gets as a type parameter):
type IFetchData =
abstract FetchData<'T> : string -> seq<'T> // Note: Generic parameter here!
You need to do something like
type IFetchData<'a> =
abstract FetchData: string -> seq<'a>
type SampleFetchData() =
interface IFetchData<char> with
member self.FetchData str =
seq {
for letter in str do
yield letter
}
i.e. the interface needs to be made generic. If you want to avoid the genericness you could use some inline constraints, rather than an interface
EDIT: Inline magic version
let inline Fetchdata string obj=
(^a: (member FetchData: string -> seq<'b> )(obj, string))
type SampleFetchData() =
member self.FetchData str =
seq {
for letter in str do
yield letter
}
Fetchdata "hello" (new SampleFetchData())
Related
I am curious as to how to add an ArrayBuffer element via a def. E.g.
def addToArray[T](data: ArrayBuffer[T]): ArrayBuffer[T] = {
return(data += T("XYZ"))
}
I tried this but no go. I assume we cannot do this generically, but I would like to know how to do this. If I do this, return(new ArrayBuffer[T]()), it works. Not the most difficult but somehow escaping me.
Just give the def your generic buffer and the element you want to add then return it:
def addToArrayBuffer[T](data: ArrayBuffer[T], elem: T): ArrayBuffer[T] = {
data += elem
data
}
println(addToArrayBuffer(ArrayBuffer(1, 2, 30), 4)) // ArrayBuffer(1, 2, 30, 4)
If you are not passing the element you want to add as a parameter to the def, then you can't add it inside the def. The idea is that you cannot create an instance of a type parameter, because instantiation requires a constructor which is unavailable if the type is unknown. This restriction is mentioned in the Java generics spec here:
Cannot Create Instances of Type Parameters: You cannot create an
instance of a type parameter. For example, the following code causes a
compile-time error:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
Wikipedia also explains this very nicely:
Java generics differ from C++ templates. Java generics generate only
one compiled version of a generic class or function regardless of the
number of parameterizing types used. Furthermore, the Java run-time
environment does not need to know which parameterized type is used
because the type information is validated at compile-time and is not
included in the compiled code. Consequently, instantiating a Java
class of a parameterized type is impossible because instantiation
requires a call to a constructor, which is unavailable if the type is
unknown.
Note that there might be a workaround to this using reflection, which is further detailed in the spec.
I'm new to Scala and have generic method written in Java:
public interface Context{
<T> Optional<T> get(String parameterName);
}
and Scala class:
class Mcls(ctx: Context){
val str = ctx.[Optional[String]]get("str").get //error
}
Is there a way to specify generic type parameter shorted then asInstanceOf[Optional[String]] in Scala?
val str: Optional[String] = ctx.get("str") should do it.
And so should val str = ctx.get[String]("str")
asInstanceOf[Optional[String]] is just incorrect in this case, even though it happens to work due to type erasure. To specify the parameter directly you'd write
ctx.get[String]("str")
which is the direct equivalent to ctx.<String> get("str") in Java.
I think you can use type alias to short this, and it's unnecessary to cast the type.
type MY_TYPE = Optional[String]
val str: MY_TYPE = ctx.get("str") //it's unnecessary get in here, since the `get` method already return `MY_TYPE`, and specify type after variable, the compiler will auto infer the generic type for this.
println(str)
I feel like I should preface this with the fact that I'm building my projects with sbt.
My problem is that, if at compile time a method returns something of an unimported type, in the file where I call the method, as long as I use type inference, everything compiles. Once I try to assign the unimported type to the var/val which I created with the return value of my function, I get a compiler error.
Lets say I have two classes in two package. Class App in package main and class Imported in package libraries. Lets further more say that we have a class ImportedFactory in the package main and that this class has a method for creating objects of the type Imported.
This code compiles just fine:
class App() {
// method return object of type Imported
val imp = ImportedFactory.createImportedObject()
}
This doesn't:
class App() {
// method return object of type Imported
val imp : Imported = ImportedFactory.createImportedObject()
}
This yet again does:
import libraries.Imported
class App() {
// method return object of type Imported
val imp : Imported = ImportedFactory.createImportedObject()
}
This seems like rather strange behavior. Is this normal for languages with type inference at compile time and I've yet to notice it until now in go/C++ due to my ignorance ?
Does one of the two valid approaches (import&explicit type vs infered) have advantages/drawback over the other ? (expect for, of course, one being more explicit and verbose and the other one being shorter)
Is this black magic or does the Scala compiler accomplish these deductions in a rather straight forward way ?
The only thing importing does is making a not fully qualified name available in the current scope. You could just as well write this:
class App() {
val imp: libraries.Imported = ImportedFactory.createImportedObject()
}
The reason you import libraries.Imported is for making the shorter name Imported available for you to write. If you let the compiler infer the type, you don't mention the type in your code, so you don't have to import its shorter name.
And by the way: this has nothing to do with dynamic casting in C++. The only mechanism at work in your code is type inference.
note: You'll get better search results with the term type inference
With val imp = ImportedFactory.createImportedObject() you are letting the compiler figure out what type imp should be based on type inference. Whatever type createImportObject returns, that's what type imp is.
With val imp : Imported = ImportedFactory.createImportedObject() you are explicitly stating that imp is an Imported. But the compiler doesn't know what you mean by that unless you... import... it.
Both approaches have merit:
inferred types
Inferred types are great for when you're throwing together code where the type should be obvious:
val i = 1 // obviously `i` is an int
val j = i + 10 // obviously still an int
It's also great for local vars/vals where the type would be too much of a pain to write
val myFoo: FancyAbstractThing[TypeParam, AnotherTypeParam[OhNoMoreTypeParams]] = ...
// vs
val myFoo = FancyThingFactory.makeANewOne()
The downside is that if you have allowed a public def/val to have an inferred type, it can be more difficult to determine how to use that method. For this reason, omitting type annotations is typically only used for simple constants, and in local vals/vars that "client code" doesn't have to look at.
explicit types
When you do want to write library-ish code (i.e. public vals/defs), the convention is to explicitly-type them.
Probably the simplest reason for this is because this:
def myLibraryMethod = {
// super complicated implementation
}
is harder to understand than
def myLibraryMethod: String = {
// super complicated implementation
}
Another benefit to explicitly-typing your code is when you want to expose a less-specific type than what the value actually is:
val invalidNumbers: Set[Int] = TreeSet(4, 8, 15, 16, 23, 42)
In this example, you don't want client code to need to care that your invalidNumbers is actually a TreeSet. That's an implementation detail. In this case you're hiding some information that, while true, would be distracting.
Background: I am trying to expand my existing logging framework, which is currently a wrapper of static non-thread-safe methods over printfn and friends. My design goals are: having a generic interface ILog and concrete classes like Dbg, Log, Trace. I cannot use modules and functions, unfortunately, because I like to leverage the ConditionalAttribute on the methods.
I have a working approach that looks something like this:
type ILog<'T, 'U, 'V> =
abstract member log: 'T -> unit
abstract member log: 'U * 'V -> unit
type Dbg<'T, 'U, 'V when 'T :> Printf.StringFormat<string> and 'U :> Printf.StringFormat<'V -> string>>() =
static member inline _do_other_stuff() = "other stuff"
static member inline private _helper() =
printfn "%s %s" (Dbg<_,_,_>._do_other_stuff())
interface ILog<'T, 'U, 'V> with
[<Conditional("DEBUG")>] // removed from call site
member this.log(msg) = sprintf msg |> Dbg<_,_,_>._helper()
[<Conditional("DEBUG")>] // removed from call site
member this.log(fmt, a) = sprintf fmt a |> Dbg<_,_,_>._helper()
module TestMe =
let test() =
let dbg = new Dbg<_,_,_>() :> ILog<_,_,_>
dbg.log("test%i", 2)
Here, the compiler and syntax checker and coloring detects properly the dbg.log("test%i", 2) line, which is exactly what I want. It will also properly raise an error if I were to write "test%s" instead.
Now, if I take the above approach and expand it to create more overloads of the ILog.log method, this gets pretty hairy pretty quickly because of all the type annotations and the required use of syntax like Dbg<_,_,_>. Some of it can be hidden away, but still I figured there must be a better way.
One approach I tried, which seemed very FSharpish is:
type ILog =
abstract member log: _ -> unit
abstract member log: _ * _ -> unit
This compiles the interface and infers the type to be 'a0 and 'a0 -> 'a1 respectively (which seems wrong, why is the second log member getting the same 'a0?). But, I can't find any way of implementing such overly generic interface:
type Dbg() =
interface ILog with
member this.log v = v + 1 |> ignore // it won't infer int here
It raises:
The declared type parameter '?' cannot be used here, since the type parameter cannot be resolved at compile time.
Does F# 4.0 have a way of declaring interfaces in a more generic way, or am I stuck to having to declare them specifically (while this works, it is tedious).
I'd like to write a type alias to shorten, nice and encapsulated Scala code.
Suppose I got some collection which has the property of being a list of maps, the value of which are tuples.
My type would write something like List[Map[Int, (String, String)]], or anything more generic as my application allows it. I could imagine having a supertype asking for a Seq[MapLike[Int, Any]] or whatever floats my boat, with concrete subclasses being more specific.
I'd then want to write an alias for this long type.
class ConcreteClass {
type DataType = List[Map[Int, (String, String)]]
...
}
I would then happily use ConcreteClass#DataType everywhere I can take one, and use it.
Now suppose I add a function
def foo(a : DataType) { ... }
And I want to call it from outside with an empty list.
I can call foo(List()), but when I want to change my underlying type to be another type of Seq, I'll have to come back and change this code too. Besides, it's not very explicit this empty list is intended as a DataType. And the companion object does not have the associated List methods, so I can't call DataType(), or DataType.empty. It's gonna be even more annoying when I need non-empty lists since I'll have to write out a significant part of this long type.
Is there any way I can ask Scala to understand my type as the same thing, including companion object with its creator methods, in the interest of shortening code and blackboxing it ?
Or, any reason why I should not be doing this in the first place ?
The answer was actually quite simple:
class ConcreteClass {
type DataType = List[String]
}
object ConcreteClass {
val DataType = List
}
val d = ConcreteClass.DataType.empty
This enables my code to call ConcreteClass.DataType to construct lists with all the methods in List and little effort.
Thanks a lot to Oleg for the insight. His answer is also best in case you want not to delegate to List any call to ConcreteClass.DataType, but control precisely what you want to allow callers to do.
What about this?
class ConcreteClass {
type DataType = List[String]
}
object DataType {
def apply(): ConcreteClass#DataType = Nil
}
//...
val a = DataType()