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)
Related
I am new to scala, and got a little doubt about function definition & default return type.
Here is a function definition:
def wol(s: String) = s.length.toString.length
The prompt says it's:
wol: (s: String)Int
But, the code didn't specify return type explicitly, shouldn't it default to Unit, which means void in Java.
So, what is the rules for default return type of a Scala function?
The return type in a function is actually the return type of the last expression that occurs in the function. In this case it's an Int, because #length returns an Int.
This is the work done by the compiler when it tries to infer the type. If you don't specify a type, it automatically gets inferred, but it's not necessarily Unit. You could force it to be that be stating it:
def wol(s: String): Unit = s.length.toString.length
EDIT [syntactic sugar sample]
I just remembered something that might be connected to your previous beliefs. When you define a method without specifying its return type and without putting the = sign, the compiler will force the return type to be Unit.
def wol(s: String) {
s.length.toString.length
}
val x = wol("") // x has type Unit!
IntelliJ actually warns you and gives the hint Useless expression. Behind the scene, the #wol function here is converted into something like:
// This is actually the same as the first function
def wol(s: String): Unit = { s.length.toString.length }
Anyway, as a best practice try to avoid using this syntax and always opt for putting that = sign. Furthermore if you define public methods try to always specify the return type.
Hope that helps :)
If I try to define an implicit conversion for a primitive type, then it doesn't seem to work. E.g.:
implicit def globalIntToString(a: Int) : String = { a.toString() + "globalhi" }
1.toInt + "hi"
The above will still return simply "1hi" as the result.
However, it seems that if I parameterize a class or a def and then pass in the implicit for the parametrized case, then it seems to work. Does anyone know what the reasons are? E.g. does this have something to do with boxing/unboxing of primtives (e.g., parameterized primitives are boxed)? Does implicit only work with reference types and not primitive types?
class typeConv[T] { implicit def tToStr(a: T) : String = { a.toString() + "hi" } }
class t[K](a: K)(tc : typeConv[K]) { import tc._; println(a + "cool"); println(1.toInt + "cool" ) }
new t(1)(new typeConv[Int])
There are a few subtle things going on here. #yan has already explained the core issue - I'll try to add some more specific information.
As noted, 1.toInt + "hi" will never use any implicit conversion because Scala Int class actually has a method + that takes a String parameter. The compiler will look for an implicit view only when it can't find matching member in the original type.
A little more complicated stuff is happening inside your t class. Scalac will look for implicit conversion from a generic type K to any type that has a + method that takes a String parameter. There will be two candidates for such a conversion: your own tc.tToStr and Scala built-in scala.Predef.any2stringadd.
Normally, any2stringadd would be used, but in your example, your own conversion is used. Why does it have precedence over any2stringadd?
During implicit search, tc.tToStr is seen as a function of type K => String, while any2stringadd is seen as a function of type Any => StringAdd. My guess is that K => String is seen by the compiler as a more specific conversion than Any => StringAdd, but someone would have to confirm it with a proper reference to Scala Language Specification.
As you can see, defining such conversions may cause you a lot of strange behaviour. I'd definitely say that introducing an implicit conversion to a String is asking for trouble.
This happens because Scala defines a + operator on the Int type that takes a String and does not need to resolve an implicit conversion. Also, converting to String is usually a bad idea, as you'd generally have a custom, one-off type that would define the methods you're trying to add.
I have this as a return type in Scala
Map[String, Seq[Map[String, Seq[MyClass]]]]
I have to use this in multiple places in my code, is there a way to assign this to a constant of sorts and use the constant instead of explicitly stating it?
Yes, you can define a type alias with type Foo = Map[...].
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())
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.