I have a scala syntax question - say I have a simple dependency pattern construct like the following
trait Master {
val foobar
object SubObject extends SubObject {
foobar = foobar
}
}
trait SubObject {
val foobar
}
Obviously, this will not compile, since the reference
foobar = foobar
is ambiguous.
How do I specify that the RHS of the expression should reference Master's foobar variable? Is there some sort of special usage of 'this' or 'self' that I should know about?
You can use the Master.this qualifier to specifically reference the outer scope, something like the following:
trait Master {
val foobar = "Hello world"
object SubObject extends SubObject {
val foobar = Master.this.foobar
}
}
trait SubObject {
val foobar:String
}
I believe the easiest way is to use a self-type definition. In addition to a bunch of cool type-theoretic effects, you can use a self-type to create an alias for "this". (Haven't tested this)
trait Master {
master =>
val foobar
object SubObject extends SubObject {
foobar = master.foobar
}
}
trait SubObject {
val foobar
}
Related
I need to change an object's behavior on run-time.
I have two concrete object (singleton) classes Dog and Cat, both extend from an abstract class Animal.
The object animal of Animal type should be changed to either Dog or Cat on runtime.
Here's the rough code of something that I am trying to accomplish:
abstract class Animal() {
def sound: Unit
}
object Cat extends Animal {
def sound: Unit = {
print("meow")
}
}
object Dog extends Animal {
def sound: Unit = {
print("bark")
}
}
object MyProgram {
val animal: Animal = _
def initialize(config: Config): Unit ={
// check the config
if (config.getString("ANIMAL_TYPE").equals("Dog")) {
animal = Dog
} else {
animal = Cat
}
}
def run: Unit = {
animal.sound
}
}
def main(): Unit = {
val config = ConfigFactory.praseFile(myconfigfile)
MyProgram.initialize(config)
MyProgram.run
}
Can something like this be done in Scala? If not, how can I accomplish this in Scala.
The error you are getting has nothing to do with typing or dynamic polymorphism:
var animal : Animal = _
^
On line 19: error: local variables must be initialized
As you can see, there is nothing wrong with the types in your program, you simply need to properly initialize your variable:
def main() : Unit = {
var animal = if(config.getString("ANIMAL_TYPE").equals("Dog")) {
Dog
} else {
Cat
}
// this should print either bark or meow
animal.sound
}
Note that there are a couple of non-idiomatic things in your code. A more idiomatic version would look something like this:
trait Animal {
val sound: String
}
object Cat extends Animal {
override val sound = "meow"
}
object Dog extends Animal {
override val sound = "bark"
}
def main(): Unit = {
val animal = if (config.getString("ANIMAL_TYPE").equals("Dog")) Dog else Cat
// this should print either bark or meow
print(animal.sound)
}
Use a trait instead of an abstract class.
Don't use an empty constructor / initializer, just use no constructor / initializer.
Separate input/output from computation: the printing should be done in the main method, not in the Animal.
Use the explicit override modifier.
Don't use type annotations if the type is obvious.
Don't use curly braces around single expressions.
Don't use var, always use val.
if is an expression, don't ignore its return value.
You are defining the main function incorrectly.
The main function should be a member of some object, and it should have an argument of the type Array[String].
object SomeRandomName {
def main(): Unit = {
var animal: Animal = null
// check the config
if(config.getString("ANIMAL_TYPE").equals("Dog")) {
animal = Dog
} else {
animal = Cat
}
// this should print either bark or meow
animal.sound
}
}
And this code should compile and run well.
SIDENOTE: If you are using Scala 3 (instead of Scala 2.x), then you don't need to make a wrapper object of the main function. The function can be at the top level.
Your code should work almost as it is, just assign something to animal.
object MyProgram {
//First of all use some default value for animal.
//It will be safer to use.
var animal: Animal = Cat
// or use explicitly null if there is no sensible default value.
// underscore makes it less clear what will happen.
//var animal: Animal = null
//I thing match is better than if/else here especially when third animal will arrive. You can assign it like that:
def initialize(config: Config): Unit ={
animal = (config.getString("ANIMAL_TYPE") match {
case "Dog" => Dog
case _ => Cat
}
}
}
I have a type hierarchy like this:
trait Description {
}
trait DescriptionProvider {
val description: Description
}
object Sample extends DescriptionProvider {
object description extends Description {
val name = "foo"
}
}
Now I am looking for a function f, which gives me the concrete value a.description for any sub type of DescriptionProvider, including it's type.
E.g. f(Sample).name should compile and evaluate to foo.
An obvious accessing method can't work of course
def obvious[T <: DescriptionProvider](x: T) = x.description
obvious(Sample).name // doesn't compile of course, as foo returns only Description.
Is there any Trick how to design such a function f without doing massive changes in the object hierarchy (which is already existent and huge)?
I already tried using a Macro, which somehow works, but IntelliJ doesn't like it (in above Example .name would appear in Red), which makes it pretty hard to use.
I am using Scala 2.10 and can't change right now.
Annotate your return type with a path-dependent one instead of relying on inference:
def obvious[T <: DescriptionProvider](x: T): x.description.type = x.description
I made a Scastie snippet with 2.10.6 and it seems to be working. I cannot check if Intellij would not complain, however.
Why don't you add name to your Description trait:
trait Description {
val name: String
}
trait DescriptionProvider {
val description: Description
}
object Sample extends DescriptionProvider {
object description extends Description {
override val name: String = "foo"
}
}
object Main extends App{
def obvious[T <: DescriptionProvider](x: T) = x.description
val description: String = obvious(Sample).name
println(s"description = ${description}")
}
Now you can compile and run the code. Once you add name to Description trait, compiler knows that a Description has a name.
In various Scala literature I see some self-type annotations using "this" and others using "self":
trait A { this: B => ... }
trait A { self: B => ... }
Is there any real difference between using "this" or "self"? Does it matter at all what name you use? Is this just as valid?
trait A { foo: B => ... }
All three forms are valid, and have the effect that B is assumed as the type of this in class A.
The first two variants
trait A { self: B => ... }
trait A { foo: B => ... }
introduce self (respectively, foo) as an alias for this in trait A. This is useful for accessing the this reference from an inner class. I.e. you could then use self instead of A.this when accessing the this reference of the trait A from a class nested within it. Example:
class MyFrame extends JFrame { frame =>
getContentPane().add( new JButton( "Hide" ) {
addActionListener( new ActionListener {
def actionPerformed( e: ActionEvent ) {
// this.setVisible( false ) --> shadowed by JButton!
frame.setVisible( false )
}
})
})
}
The third variant,
trait A { this: B => ... }
does not introduce an alias for this; it just sets the self type.
There is a difference in that this always refers to the object defined by the innermost template.
The expression this can appear in the statement part of a template or compound type. It stands for the object being defined by the innermost template or compound type enclosing the reference. If this is a compound type, the type of this is that compound type. If it is a template of a class or object definition with simple name C, the type of this is the same as the type of C.this. (Scala Ref. §6.5)
So, if you call your self-type foo, you could still refer to it as this (unless, of course, you are in an inner template in which case this will refer to the object defined by it – and unless you don’t give the inner template’s self-type the same name) but obviously not the other way round.
say I have the following code:
package my
class Foo
class Bar extends Foo
object Chooser {
val isFoo = true
}
I import Foo as:
import my.{Foo => MyClass}
I want to be able to do something like:
If Chooser.isFoo, then:
import my.{Foo => MyClass}
else:
import my.{Bar => MyClass}
I have used Foo in my code as something like this:
object MyObj {
val a = new MyClass
// ...
}
Are there any hidden features of Scala that let me use Bar in place of Foo without modifying the code of MyObj at all. Also what would be the best way to design such code in future so that such extensions are easy?
There isn't but I'm guessing you are more interested in different implementations at runtime than in conditional type import. Your Chooser.isFoo sounds like something that happens during runtime and not in the type system.
One example of how you could do it, since the common type for Foo and Bar is Foo:
val a: Foo =
if (Chooser.isFoo) new my.Foo
else new my.Bar
Edit based on your edit: you could delay the choice by having an abstract type or a type parameter, like so:
class MyObj[T :> Foo] {
val a: T
}
val anInstance = new MyObj[Foo]
val anotherInstance = new MyObj[Bar]
Note the type bound that says that T must be a subclass of Foo, or else you wouldn't know anything about what you can do with a T.
Happen to see this old post & a little curious why it can't do conditional imports in Scala? Maybe old version limit, not sure? But see this, we can import in any place of scala code.
For your scenario, it could be:
try.scala:
package my
class Foo {
}
class Bar extends Foo
object Chooser {
val isFoo = true
}
object MyObj extends App {
if (Chooser.isFoo) {
import my.{Foo => MyClass}
val a = new MyClass
println(a)
} else {
import my.{Bar => MyClass}
val a = new MyClass
println(a)
}
}
run output:
C:\abc\abc>scalac try.scala
C:\abc\abc>scala my.MyObj
my.Foo#6f4a47c7
I want to make the following example so that Collar is immutable
trait Collar{
var text:String="";
}
class dog(val name:String){
def bark()= ...
}
val snoopy = new dog("snoopy") with Collar;
snoopy.text="charley's dog";
println(snoopy.text)
However when I try something like
trait Collar(val text:String){
}
I get the compile time error
traits or objects may not have parameters
Is there currently a a way to do this? If not, why not?
Remember, a good dog shouldn't care when it has a Collar.
Not at all sure what your real question is, but perhaps this is what you're looking for:
trait Collar{
val tagText: String // 'val', not 'var'; left undefined here
}
class Dog(val name:String) {
def bark()= ...
}
val snoopy = new Dog("snoopy") with Collar {
val tagText= "charley's dog"
}
println(snoopy.tagText)
Alternatively, Collar.tagText can be set with an initial/default value AND also be overridden where Dog is instantiated.