I would like to write this in Scala:
var b: Map[String, Int] = Map()
def method() = {
def a_=(i: Int) = b += "method" -> i
// ...
a = 2
}
But this complains saying that a is not defined. Why is that? I thought a = ... was rewritten to a_=(...).
Solution: Thanks to Jörg, i works, one has to provide the getter and make the method top-level:
var b: Map[String, Int] = Map()
def a_=(i: Int) = b += "method" -> i
def a: Int = ??? // Dummy
def method() = {
// ...
a = 2
}
This compiles.
Why is that? I thought a = ... was rewritten to a_=(...).
No.
You need both a getter and a setter for the re-write to take effect.
The re-write only happens when there is something to re-write, i.e. field access of an object, class, or trait.
See section 6.15 Assignments of the Scala Language Specifiation (bold emphasis mine):
If x is a parameterless function defined in some template, and the same template contains a setter function x_= as member, then the assignment x = e is interpreted as the invocation x_=(e) of that setter function.
you cannot override assignment operator, since it's a reserved word. what you can do is this:
object BAndA {
var b: Map[String, Int] = Map()
def a = b // getter
def a_=(i: Int) = b += "method" -> i // setter
}
object Test extends App {
import BAndA._
a = 1
println(b)
}
getter is requried
Related
In Scala, I want to generate some aliases for basic types, and then implement conversions through a type class. This is both useful for me, and an opportunity to understand type classes. The code is the following:
type Index = Int
val Index = Int
type Integer = Int
val Integer = Int
type Real = Double
val Real = Double // to have companion object of Double also be the companion object of Real
trait Convertible[A] {
def toIndex(a: A): Index
def toInteger(a: A): Integer
def toReal(a: A): Real
}
implicit val ConvertibleIndex: Convertible[Index] = new Convertible[Index] {
def toIndex(i: Index) = i
def toInteger(i: Index) = i
def toReal(i: Index) = i.toDouble
}
implicit val ConvertibleInteger: Convertible[Integer] = new Convertible[Integer] {
def toIndex(i: Integer) = i
def toInteger(i: Integer) = i
def toReal(i: Integer) = i.toDouble
}
implicit val ConvertibleReal: Convertible[Real] = new Convertible[Real] {
def toIndex(r: Real) = r.toInt
def toInteger(r: Real) = r.toInt
def toReal(r: Real) = r
}
implicit val ConvertibleString: Convertible[String] = new Convertible[String] {
def toIndex(s: String) = s.toInt
def toInteger(s: String) = s.toInt
def toReal(s: String) = s.toDouble
}
implicit class ConvertibleSyntax[A](a: A)(implicit val c: Convertible[A]) {
def toIndex = c.toIndex(a)
def toInteger = c.toInteger(a)
def toReal = c.toReal(a)
}
Consider now:
val a = 3.toReal
val b = 3.0.toReal
val c = "3".toReal
The statement for a does not compile, with the compilation error: method toReal is not a member of Int. But, for the b and c statements, the implicit conversion to ConvertibleSyntax is properly done.
Why is the implicit conversion not working on Int, but is working on Double and String ?
Because you define ambiguous implicits for Index and Integer (both Int).
Which one should be chosen by compiler?
I think you might be a little confused about how Scala does implicit conversions. (A common mistake, as implicit is a little overused.)
I think that what you want, first of all, is an implicit conversion function - or even an implicit class. Here's how you could do this using the latter:
Note: Int, Index and Integer are treated identically, so are Real and Double, confusing matters somewhat, so I've pared this down to something that will work. Also, Convertible does not need to be generic as its conversion functions need no arguments. Finally, you shouldn't have both type and val declarations for your types.
type Index = Int
type Integer = Int
type Real = Double
trait Convertible {
def toIndex: Index
def toInteger: Integer
def toReal: Real
}
// Implicit classes cannot be defined in top-level scope, so they belong to an object.
object Implicits {
implicit class ConvertibleInt(i: Int)
extends Convertible {
override def toIndex = i
override def toInteger = i
override def toReal = i.toDouble
}
implicit class ConvertibleDouble(d: Double)
extends Convertible {
override def toIndex = d.toInt
override def toInteger = d.toInt
override def toReal = d
}
implicit class ConvertibleString(s: String)
extends Convertible {
override def toIndex = s.toInt
override def toInteger = s.toInt
override def toReal = s.toDouble
}
}
Now try this:
import Implicits._
val a = 3.toReal
val b = 3.0.toReal
val c = "3".toReal
What's happening here? Well, the implicit class declarations define classes that decorate the sole constructor argument with additional functions. If the compiler sees that you're trying to call a method on a type that doesn't have that method, it will look to see if there's an implicit conversion, in scope, to a type that does. If so, it is used and the function is called; if not, you get a compiler error. (The import statement is used to bring the classes into your current scope.)
So, for example, when the compiler sees "3".toReal it firstly determines that "3" is a String. Since this type doesn't have a .toReal member, it tries to find a conversion from a String to a type that does have such a member. It finds the ConvertibleString implicit class that takes a String argument and provides a .toReal method. Yay! So the compiler creates an instance of this class by passing "3" to ConvertibleString's constructor, then calls .toReal on the result.
On the other hand, when implicit is used with a value, it tells the compiler that the value is a default for any matching implicit arguments of the same type that are not provided. NEVER USE implicit WITH A PRIMITIVE OR COMMON LIBRARY TYPE!
For example:
final case class Example(i: Int)
// Default.
implicit val nameCanBeAnythingAtAll = Example(5)
// Function with implicit argument.
def someFunc(implicit x: Example): Unit = println(s"Value is $x")
Now, if you write something like this:
someFunc
the output will be Value is Example(5).
implicit values and arguments are an advanced topic, and I wouldn't worry about how they're used right now.
When assigning a function using an unapplied method, it appears that named and default parameters are lost. Is there any way to avoid this?
def foo(namedParam: String = "defaultValue") = namedParam*2
// scala> foo()
// res8: String = defaultValuedefaultValue
def bar = foo _
// scala> bar()
// <console>:28: error: not enough arguments for method
// apply: (v1: String)String in trait Function1.
// Unspecified value parameter v1.
The reason I want to do this is to bundle my imports in a single file, i.e.
myproject/imports.scala
object imports {
def externalAPIFunction = myproject.somepackage.internalFunction _
}
scala shell
import myproject.imports._
externalAPIFunction() // no named or default arguments :(
Any way to do this or do I have to put my default arguments in the external function definition?
Functions (i.e. values of type Function<N>[...]) simply can't have default or implicit parameters in Scala, only methods can. And method _ returns a function: that's what it's for. So yes, to achieve your purpose you'd need to write
object imports {
def externalAPIFunction(namedParam: String = "defaultValue") =
myproject.somepackage.internalFunction(namedParam)
}
You can avoid duplication using
object imports {
val x = myproject.somepackage
}
// elsewhere
import myproject.imports._
x.internalAPIFunction()
// or
import myproject.imports.x._
internalAPIFunction()
which may or may not be good enough for your purposes.
I think you need to use currying.
def foo()(namedParam: String = "defaultValue") = namedParam * 2
//> foo: ()(namedParam: String)String
// scala> foo()
// res8: String = defaultValuedefaultValue
def bar() = foo() _ //> bar: ()String => String
bar() //> res0: String => String = <function1>
Here's a common annoyance for me:
trait Foo {
val x: Int
}
def foo(x: Int) = new Foo {
val x = x // <-- Here
}
I probably run into this about once every 20 minutes when coding Scala.
The solutions that I am aware of, and their respective deficiencies, are:
Enclose the local declaration in an object which can be named -- Doesn't work for parameters.
Make an alias -- Verbose if you need to preserve the path dependent type.
Use a proxy constructor -- Cumbersome in the presence of dependently typed fields.
Are there any others?
I sometimes use this cheesy approach:
def foo(x: Int): Foo = {
val x1 = x
new Foo {
val x = x1
}
}
How about this?
trait Foo {
val x: Int
}
object Foo {
def apply(xt: Int) = new Foo { val x = xt }
}
def foo(xt: Int) = Foo(xt) // <-- Here
Following is a Scala class with constructors. My questions are marked with ****
class Constructors( a:Int, b:Int ) {
def this() =
{
this(4,5)
val s : String = "I want to dance after calling constructor"
//**** Constructors does not take parameters error? What is this compile error?
this(4,5)
}
def this(a:Int, b:Int, c:Int) =
{
//called constructor's definition must precede calling constructor's definition
this(5)
}
def this(d:Int)
// **** no equal to works? def this(d:Int) =
//that means you can have a constructor procedure and not a function
{
this()
}
//A private constructor
private def this(a:String) = this(1)
//**** What does this mean?
private[this] def this(a:Boolean) = this("true")
//Constructors does not return anything, not even Unit (read void)
def this(a:Double):Unit = this(10,20,30)
}
Could you please answer my questions in the **** above? For example Constructors does not take parameters error? What is this compile error?
Ans 1:
scala> class Boo(a: Int) {
| def this() = { this(3); println("lol"); this(3) }
| def apply(n: Int) = { println("apply with " + n) }
| }
defined class Boo
scala> new Boo()
lol
apply with 3
res0: Boo = Boo#fdd15b
First this(3) is a delegation to primary constructor. The second this(3) invokes this object's apply method i.e. expands to this.apply(3). Observe the above example.
Ans 2:
= is optional in constructor definitions as they don't really return anything. They have different semantics from regular methods.
Ans 3:
private[this] is called object-private access modifier. An object cannot access other object's private[this] fields even though they both belong to the same class. Thus it's stricter than private. Observe the error below:
scala> class Boo(private val a: Int, private[this] val b: Int) {
| def foo() {
| println((this.a, this.b))
| }
| }
defined class Boo
scala> new Boo(2, 3).foo()
(2,3)
scala> class Boo(private val a: Int, private[this] val b: Int) {
| def foo(that: Boo) {
| println((this.a, this.b))
| println((that.a, that.b))
| }
| }
<console>:17: error: value b is not a member of Boo
println((that.a, that.b))
^
Ans 4:
Same as Ans 2.
Related to question 2 is:
Scala Auxilliary Constructor behavior
This is causing the error, the lack of (default) parameters for int b and int c throws called constructor's definition must precede calling constructor's definition
I'm trying to define a class which will have as a field a Set, and would like to be able to manipulate this set directly from the container class:
case class MyClass(prop: String) extends TraversableLike[Int,MyClass] {
private def mySet: Set[Int]() = Set()
override def foreach[U](f: Int => U) = data.foreach[U](f)
override def newBuilder: Builder[Int, MyClass] =
new ArrayBuffer[Int] mapResult (a => MyClass(prop, a.toSet))
implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
new CanBuildFrom[MyClass, Int, MyClass] {
def apply(): Builder[Int, MyClass] = newBuilder
def apply(from: MyClass): Builder[Int, MyClass] = newBuilder
}
}
I'd like to be able to do
var obj = MyClass("hello")
obj += 1
obj = obj map (_+1)
The first instruction (obj+= 1) works, but the second doesn't.
The problem is that I can't put my implicit canBuildFrom into an object MyClass because builder needs informations dependant of the instance (in this case, the prop field).
Is there a solution make my implicit accessible and keep its instance dependance ?
I'd like to avoid making my class mutable.
There are a couple of problems with your code:
Set[Int]() is not a valid type for mySet, you should drop the ()
member mySet should be a val, not a def
you are calling apply() methods that don't exist
if you want to hook in into the collections hierarchy at the Traversable level, you don't get methods like + and the derived +=. If you're representing a set, then it should be a Set.
Here's a revised attempt:
import mutable.Builder
import generic.CanBuildFrom
class MyClass private (val prop: String, private val mySet: Set[Int] = Set())
extends immutable.Set[Int] with SetLike[Int, MyClass] {
def -(elem: Int) = MyClass(prop, mySet - elem)
def +(elem: Int) = MyClass(prop, mySet + elem)
def contains(elem: Int) = mySet.contains(elem)
def iterator = mySet.iterator
override def empty: MyClass = MyClass(prop)
override def stringPrefix = "MyClass(" + prop + ")"
}
object MyClass {
def DefaultProp = "DefaultProp"
def apply(prop: String, mySet: Set[Int] = Set()) = new MyClass(prop, mySet)
def newBuilder(prop: String = DefaultProp): Builder[Int, MyClass] =
Set.newBuilder[Int] mapResult (set => MyClass(prop, set))
implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
new CanBuildFrom[MyClass, Int, MyClass] {
def apply(): Builder[Int, MyClass] = newBuilder()
def apply(from: MyClass): Builder[Int, MyClass] = newBuilder(from.prop)
}
}
Then you can write:
var obj = MyClass("hello")
obj += 1
println(obj) // prints MyClass(hello)(1)
obj = obj map (_ + 1)
println(obj) // prints MyClass(hello)(2)
Let's dissect that:
MyClass is now explicitly an immutable set with a custom representation declared in the type arguments to SetLike. prop is a public val member; the actual set, mySet, is a private val.
Then we need to implement the four operations on which Set relies, by simply forwarding them the mySet. (This looks a like it could be factored out. For the Seqs, there is a class SeqForwarder that does a similar job; I couldn't find a SetForwarder, though). Finally, we provide an empty method, on which the built-in inherited builder also relies. Finally, overriding stringPrefix enables a nicer string representation with "MyClass" and the value of prop.
Note that The canBuildFrom object MyClass calls newBuilder, passing the prop of the original collection when it can. This means that most of the time, you can keep this value while mapping, etc. over MyClass instances. We need to define a default value for prop, however, since CanBuildFroms must define an apply method that does not tell what the originating collection is. (Question: why would this actually happen?)
Finally, our implementation of newBuilder does not rely on ArrayBuffers any more, but directly builds the Set instance that will be wrapped by your new MyClass instance.
Some more resources:
http://www.scala-lang.org/docu/files/collections-api/collections-impl.html
Implement a scala collection so that map, filter, etc. produce the right type