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
Related
If I have the following code:
trait MyTrait {
val x: Int
}
def f(_x: Int) = new MyTrait {
val x = _x
}
If I were to define my function as follows:
def f(x: Int) = new MyTrait {
val x = x
}
This would be incorrect as val x is just referring to itself. Is there a way I can avoid having to use a different name for 'x' when I want to refer to something in the outer scope?
You can, but only if the outer scope x is a member of enclosing type, not a method parameter or a local variable:
class MyOuter(val x: Int) {
def f() = new MyTrait {
val x = MyOuter.this.x
}
Not really: in the scope of MyTrait, x refers to the field. However, you have the option to wrap parameter into some other name before you enter that scope:
def f(x: Int) = {
val xn = x
new MyTrait {
val x = xn
}
}
Well, in this particular case, you could write something like this:
def f(x: Int) = {
class Foo(val x: Int = x) extends MyTrait
new Foo
}
Not sure what exactly it makes better over just renaming x to y though ...
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
I'm quite new to Scala and a part of my project ended up with the following design.
trait StringService {
def length(s: String): Int
def vowels(s: String): Int
}
Those methods are used as parameters to
def processStrings(operation: String => Int) = {...}
Calls like processStrings(ss.length) work fine. Now I would like to abstract
the type of these methods
type StringFuction = String => Int
The problem is that an implementation like
override def length(s: String): Int = { ... }
is no longer valid. Of course, I can go with
override def length: StringFunction = { (s: String) => ... }
but this seems a little off.
What's the proper way? Please feel free to suggest a different design if this isn't a true Scala approach.
Well, there are different ways to do this, depending on the purpose you want to use your type alias for. This works for example:
type StringFunction = String => Int
trait Foo { def foo(s: String) = ??? }
class Bar extends Foo {
def foo(s: String) = s.length
}
def foobar(f: StringFunction)(s) = f(s)
foobar(new Bar().foo)("bar")
This works too:
type StringFunction = String => Int
trait Foo { def foo: StringFunction = ??? }
class Bar extends Foo {
override def foo = _.length
}
def foobar(f: StringFunction)(s) = f(s)
foobar(new Bar().foo)("bar")
Strictly speaking, these are not the same constructs: in the first case Foo.foo is a method, that takes an String argument and returns an Int.
In the second case, it is a method, that takes no arguments, and returns a lambda function, that take a String argument, and returns an Int.
This difference is fairly subtle though. It does matter for some specific cases, but often can be ignored.
I have a use case similar to the situation following:
trait A {
implicit val x = "hello"
}
class B {
// somehow bring x into scope here???
def run(x: Int)(implicit y: String) = y + x
}
println((new B).run(3))
I understand that I need to bring x defined in the trait in the implicit scope of B. I've already tried the following:
# attempt 1 #
class B extends A { .... } /// doesn't work
# attempt 2 #
class B extends A {
val x1 = implicitly[String] /// doesn't work either
def run(x: Int)(implicit y: String) = y + x
}
Please explain what am I missing here (or, point me to relevant theory topic which I can study, fairly new to scala).
The value of 'implicit y' will be resolved in your println-line where it is not available. You are making the variable implicitly available within the body of the class, but resolution of implicit String is not needed there.
Implicit isn't magic; if you can't reach the implicit variable explicitly then so can't the compiler.
What problem are you really trying to solve?
Wrap your whole code in a object and extend trait A in class B :
object P {
trait A {
implicit val x = "hello"
}
class B extends A {
def run(y: Int) = y + x
}
def f = println(new B().run(3))
}
Output :
scala> P.f
3hello
I'm trying to define a macro in a trait. For example,
trait Macro {
val magic: Int = 1001
def doMagic(x: Int): Int = macro Impl.doMagic
}
object Impl {
def doMagic(c: Context)(x: c.Expr[Int]): c.Expr[Int] = ???
}
What I'm trying to do here is, the doMagic implementation should be able to refer to the field magic in the trait Macro, type-safely.
I tried to refer to this by This(c.enclosingClass.asModule.moduleClass), but it seems to refer the tree of macro application, which resulting an anonymous class called $iw. So in my understanding the Enclosures is where the macro is being applied, not where it's being defined.
Is there anyway I can do this?
This does not answer the question directly, but maybe it helps nonetheless. You could pass the instance as parameter to the macro and to hide this from the caller you could add a corresponding method delegating to doMagic like this:
trait Macro {
val magic: Int = 1001
def doMagic(m: Macro, x: Int): Int = macro Impl.doMagic
}
object Impl {
def doMagic(context: Context)(m: context.Expr[Macro], x: context.Expr[Int]): context.Expr[Int] = {
import context.universe._
reify(m.splice.magic + x.splice)
}
}
the wrapper-trait:
trait Macro2 extends Macro {
def doMagic2(x: Int): Int = doMagic(this, x)
}
and the caller:
val z = new Macro2 {}
println(z.doMagic2(5))
I sorted it out. We should use c.prefix, like
val self = TermName(c.freshName("self"))
c.Expr[T] {
q"""
val $self = ${c.prefix.tree}
...
"""
}
And a self variable can be used to capture the prefix, so it's only evaluated once.