I am a newbie and I will try to be as clear as possible. This is about odersky scala course.
I have this code below. I understand that this is an alias type to define a Scala Set differently that the traditional way you define a Set in Scala(i.e. a Scala collection). In this type alias, you give it a integer and returns true (somehow) if the item is contained in the Set.
type Set = Int => Boolean
Now I have this piece of code, which returns the result i am expecting.
val a = Set("element is contained in set")
type Set = Int => Boolean
a.contains("element is contained in set")
a.contains("element IS NOT contained in set")
The result is:
a: scala.collection.immutable.Set[String] = Set(element is contained in set)
defined type alias Set
res0: Boolean = true
res1: Boolean = false
res2: scala.collection.immutable.Set[String] = Set(element is contained in set)
Great! Now i introduce a line in the code.
val a = Set("element is contained in set")
type Set = Int => Boolean
a.contains("element is contained in set")
a.contains("element IS NOT contained in set")
**def custom_fc(x:Double): Set[String] = Set(x.toString)**
I get the error:
Error:(8, 24) A$A235.this.Set does not take type parameters
def custom_fc(x:Double): Set[String] = Set(x.toString)
Error:(38, 97) inst$A$A.Set does not take type parameters
println("custom_fc: " + MacroPrinter211.printGeneric({import inst$A$A._ ;def `custom_fc(x:Double): Set[String] = Set(x.toString) }).replace("inst$A$A.", ""))`
WHY? In this line i am just trying to define a regular fc (i.e. custom_fc) taking Int as input and returning a traditional scala datastructure Set[String]
type Set = Int => Boolean
**def custom_fc(x:Double): Set[String] = Set(x.toString)**
Why does my custom fc definition interfere with the alias before it?
My custom_fc is
custom_fc(x:Double): scala.collection.immutable.Set[String] =
scala.collection.immutable.Set(x.toString)
thank you
ps. a way to use Type Set = Int => Boolean
val belowNegFive: Set = (i) => i < -5
belowNegFive(10)
Return a bool dependinf if the elem 10 pertains to the set of numbers below -5.
Here's what's going on.
val a = Set("element is contained in set") // a is old library Set()
type Set = Int => Boolean // alias now hides library Set()
a.contains("element is contained in set") // a is still old library
a.contains("element IS NOT contained in set") // and works like it should
def custom_fc(x:Double): Set[String] = Set(x.toString) // WRONG
// new Set alias works different from old library Set()
The point of the class is to work with functions. The Set alias is a function definition: Int => Boolean i.e. takes an Int and returns a Boolean.
The new Set alias is very different from the Set collection and can't be used the same way. The Set alias does appear to imitate the collection only in that you can query its "content" in the same way, but only when working with Int values. Even then, the means of initialization is different.
val libSet: collection.Set[Int] = Set(7) // initialize with a 7
type Set = Int => Boolean
val newSet: Set = (x:Int) => x == 7 // initialize with a 7
libSet(7) // true
libSet(4) // false
newSet(7) // true
newSet(4) // false
The library collection works with other types but the Set alias only takes an Int and returns a Boolean. The new Set is a type alias for a function definition. An instance of the new Set is a function that imitates only a small subset of what the real Set does.
So you're obviously overriding the Set alias that was already in place. You can fix this by as mentioned in the comments, specifying exactly which Set you mean.
def custom_fc(x:Int): scala.collection.immutable.Set[String] = Set(x.toString)
Also note your type alias is not doing anything. Your calls a("element is contained in set")
a("element IS NOT contained in set") are just calling the apply method on a, which is the same thing as doing a.apply(...) and a.contains(...) In order to make it easier on yourself and less confusing overall, maybe change the name to Contains?
To see an example of your set being used, here you go...
val setBeingUsed: Set = Set(1).contains
setBeingUsed(1) // true
The method which takes in an Int and returns a boolean can be assigned the type Set because you aliased that type to it. Then we can call the val we made with type Set and essentially do the same thing as calling contains on the set.
Related
Given the following test case, there are 3 scenarios in it. I would ask what's the rules here that govern when we must and when we don't have to specify the type parameter
#Test
def testTypeParamter(): Unit = {
class Cat[A]
//1. Don't need to specify the type parameter for Cat
def getCat() = new Cat
println(getCat())
import scala.collection.mutable.ArrayBuffer
//2. Don't need to specify the type parameter for ArrayBuffer
val bf = new ArrayBuffer()
println(bf)
//3. Do need to specify the type parameter for ArrayBuffer to make bf2 += 1 work
val bf2 = new ArrayBuffer[Int]()
bf2 += 1
println(getCat())
}
Compared with #2 and #3, what can we do if we create an empty ArrayBuffer without type parameter
Let's check in REPL,
1.1 scenario without a type param
scala> class Bag[A]
defined class Bag
scala> def createBag = new Bag
createBag: Bag[Nothing]
1.2 ArrayBuffer[T] without type param
scala> val buffer = new ArrayBuffer()
buffer: scala.collection.mutable.ArrayBuffer[Nothing] = ArrayBuffer()
In both case you see the default type parameter as scala.Nothing. scala.Nothing is abstract and can not be instantiated which means you can't operate on your generics instance like
buffer+=new String("apple") etc because Nothing is at the bottom of scala class hierarchy.
2. providing type parameter
This is obviously the purpose of having generic type that you want Generics for certain type.
scala> var buffer = new ArrayBuffer[Long]()
buffer: scala.collection.mutable.ArrayBuffer[Long] = ArrayBuffer()
scala> buffer+=89l
res0: scala.collection.mutable.ArrayBuffer[Long] = ArrayBuffer(89)
You don't need to specify the type parameter when Scala infers the type you want. This inference is based both on arguments to method/constructor (none in your case) and on expected type (none in your case). You could also have e.g.
val buffer: ArrayBuffer[Long] = new ArrayBuffer()
I want to map a stream of Doubles to a method which takes two parameters, one of them has a default value. I want to use the default parameter so my method has only 1 parameter which I need to pass:
def pow(x:Double, exponent:Double=2.0) = {
math.pow(x,exponent)
}
I've found out that the following works, but I do not understand why:
val res = (1 to 100).map(_.toDouble).map(pow(_))
I'm especially confused because the following does not work (compiler error because of missing type information):
val pow2 = pow(_)
val res = pow2(2.0)
println(res) // expect 4.0
The compiler is not able to infer the type that you will provide to pow2. In the res mapping you explicitly feed it a collection of Doublesand therefore pow(_) does not complain. However, in the case of val pow2 = pow(_) it complains that type parameter is missing. Change it to
val pow2 = pow(_: Double)
val res = pow2(2.0)
println(res)
and it will work just fine. pow(_) will be expanded two x => pow(x) and at this point the compiler cannot infere what's x without the type annotation.
I have read that null should not be used in scala.
How can I leave myVar uninitialized without the use of null?
class TestClass {
private var myVar: MyClass = null
}
I understand I can just make a dummy MyClass, that is never used in place of the null. But this can and does reduce the code's understandability.
As Rado has explained I can change null as shown below. I understand that I can now check to see if the variable is set during run-time, however, if I don't program that check then there is no benefit of using Option in this case.
Coming from Java, I feel there should be a way to simply leave the var uninitialized at compile-time and let it set during run-time without using the Option class, because as I mentioned above, if I don't code for the unset case then why use Option?
class TestClass {
private var myVar: Option[MyClass] = None
private def createVar() {
myVar = Some(new MyClass)
x: MyClass = myVar.get
}
}
I am thinking the only other way of doing what I am asking is:
class TestClass {
// Using dummy MyClass that will never be used.
private var myVar: MyClass = new MyClass
private def process(myVar: MyClass) {
this.myVar = myVar
myVar.useVarMethod()
}
}
The Scala way is to declare the variable as Option[MyClass]:
class TestClass {
private var myVar: Option[MyClass] = None
private def createVar() {
myVar = Some(new MyClass)
}
// Usage example:
def useMyVar(): Unit = {
myVar match {
case Some(myClass) => {
// Use myClass here ...
println(myClass.toString)
}
case None => // What to do if myVar is undefined?
}
}
}
That way you avoid NullPointerException. You make it explicit that the variable can be in undefined state. Everytime you use the myVar you have to define what to do if it is undefined.
http://www.scala-lang.org/api/current/index.html#scala.Option
I need myVar to be of type MyClass not Option[MyClass]. I see that I
could use Rado's updated answer and then use the get method, but is
there any other way?
When you use Option you can telling the compiler and everyone else who will read/use your code that it's okay not to define this value and the code will handle that condition and not fail at runtime.
The other way of dealing with is to do null checks every time before you access the variable because it could be null and therefore throw an exception at runtime.
When you use Option, the compiler will tell you if at compile time that you have not handled a condition where the value of a variable maybe undefined.
If you think about it, it's really a big deal. you have converted a runtime exception (which is deterministic) to a compile-time error.
If you want to extract the value out of something like an Option (which supports map and also flatMap), then you don't necessarily have to keep doing pattern matching on whether or not the Option contains a value (i.e. is a "Some") or not (i.e. is a "None").
Two methods are very useful - if you want just alter (or "map") the value within the Option then you can use the map method, which takes a function with a general type of:
f: A => B
so in your case at compile time would end up being:
f: MyClass => B
When you map an option, if the option is a "Some" then the contained value is passed through to the mapping function, and the function is applied (to change the MyClass to a B if you like...) and the result is passed back wrapped in an Option. If your Option is a None, then you just get a None back.
Here's a simple example:
scala> case class MyClass(value : String)
defined class MyClass
scala> val emptyOption : Option[MyClass] = None
emptyOption: Option[MyClass] = None
scala> val nonEmptyOption = Some(new MyClass("Some value"))
nonEmptyOption: Option[MyClass] = Some(MyClass(Some value)
Try and extract the value from both option instances using map:
scala> nonEmptyOption map { s => s.value + " mapped" }
res10: Option[String] = Some(Some value mapped)
scala> emptyOption map { s => s.value }
res11: Option[String] = None
So basically, if you map across an empty option, you always get a None. Map across a non-empty Option and you can extract the contained value and transform it and get the result wrapped back in an Option. Notice that you don't need to explicitly check any patterns...the map method takes care of it.
Flatmap is a bit more challenging to explain, but it basically isn't massively different except that it takes a function which has type:
g: A => M[B]
which basically allows you to take the value out of the Option (the 'A' in the type signature above), do something to it (i.e. a computation) and then return the result ('B') - wrapped in another container such as another Option, List...
The same notion (across Option anyway) that if the Option is a None then nothing really happens still applies. flatMap and map form the basis of Scala "for comprehensions" which you can read about (and are done far more justice than I could!!) in lots of other places.
I have the following Scala code snippet:
type Set = Int => Boolean
def contains(s: Set, element:Int): Boolean = s(element)
def singletonSet(element: Int): Set = Set(element)
val oneElementSet = singletonSet(5)
contains(oneElementSet, 5) // true
contains(oneElementSet, 6) // false
I'm trying to wrap my head around what this does: Set(element). Looks like it'll substitute element in place of an Int argument, to produce this: 5 => Boolean. There is no comparison anywhere, so why does oneElementSet(5) returns true, and oneElementSet(6) returns false?
Thanks!
Scala has separate namespaces for types and values. Your type alias defines what Set is in the type namespace, but in the definition of singletonSet Set comes from the value namespace, in fact it is the companion object scala.collection.immutable.Set. Set(element) invokes the apply method of the companion object, which returns a scala.collection.immutable.Set[Int], which turns out to be a subtype of Int => Boolean and therefore is a Set (your type alias) as well.
Why do the default values here behave differently when assigned explicitly to a val, versus printed directly?
package blevins.example
class SimpleWrap[T] {
var t: T = _
def get = t
}
object App extends Application {
val swb = new SimpleWrap[Boolean]
val b = swb.get
println("b: " + b) // b: false
println("swb.get: " + swb.get) // swb.get: null
val swi = new SimpleWrap[Int]
val i = swi.get
println("i: " + i) // i: 0
println("swi.get: " + swi.get) // swi.get: null
}
I'm using 2.8r19890.
Edit - It seems the strangeness happens when "get" is called expecting an Any.
val any1: Any = swb.get
val any2: Any = b
println("any1: " + any1) // any1: null
println("any2: " + any2) // any2: false
I'm pretty sure that this is something to do with boxing/unboxing of the primitives. If you write generic code to work on primitives, you have to box the primitive and then unbox it at the place you've used it as a primitive. I am not sure what unboxing algorithm is used, but I suppose it is along the following lines:
if(box == null)
default value
else
box.unbox
Therefore, very strangely I might add, the default value of the field t in your simple wrapper class is always going to be null, as the field is always going to be a boxed primitive, as generics are implemented at the JVM level by type erasure. Therefore, all the JVM sees is that t is of type Object, with a value of null. The method get will therefore always return null, but when the generic method get is supposed to return a primitive type, the null gets unboxed to the default value.
Also, a bit of poking around with reflection does indeed show that the field is indeed null.
val sw = new SimpleWrap[Boolean]
sw.getClass.getDeclaredFields.map {
f => f.setAccessible(true)
f.get(sw)
}
Oh the fun of nulls. One solution to this problem would be to use the 2.8 #specialised annotation, if that has been implemented in the nightly build you use.
Or, even better, the Scala compiler could default those fields to boxed defaults of the actual defaults of the primitives used. For example, in the case of a SimpleWrap[Boolean], t would have the type Object and the value java.lang.Boolean(false) at runtime.
EDIT: Bug report submitted.
Another weird thing:
val x: Int = null.asInstanceOf[Int] // 0
val y: Boolean = null.asInstanceOf[Boolean] // false
This is something that should be solved in order for generics to really be generic, and have consistent behaviour! At the moment your get method doesn't have a consistent behaviour.
-- Flaviu Cipcigan