Can I pass arguments to Scala class constructor that are not stored into class itself?
I want to achieve functionality which in Java could be written as follows:
class A {
private final SomethingElse y;
public A(Something x) {
y = x.derive(this);
}
}
I.e. class constructor takes parameter that is later transformed to another value using reference to this. The parameter is forgotten after constructor returns.
In Scala I can do:
class A(x: Something) {
val y = x.derive(this)
}
But it means that x is stored in the class, which I want to avoid. Since x.derive method uses reference to this, I can not make the transformation in companion object.
But it means that x is stored in the class, which I want to avoid.
If you don't reference constructor argument anywhere except the constructor itself, field won't be created. If you reference x e.g. in toString(), Scala will automatically create and assign private val for you.
Use javap -c -private A to verify what kind of fields are actually created.
BTW you pass this inside a constructor, which means a.derive() gets a reference to possibly non-initialized instance of A. Be careful!
Related
if all data types of dart language is class so
why when it's not assigned like that
int y = int(); or int(45);
String x = String(); or String ('Ahmed');
it's confused me
All Dart values are objects.
All non-function values are instances of a specific class and implements a number of interfaces.
(Function values can technically be seen as each having their own class, but in practice those classes don't really exist. Function values still implement the class interfaces Function and Object.)
Dart classes can have different constructors. There is no rule that a Dart class must have an unnamed constructor taking zero or one arguments.
If you write int y = int();, you get an error because the int class does not have an unnamed zero-argument constructor.
The same way int(45) is invalid because the int class doesn't have an unnamed one-argument constructor.
(The only constructor the int class has is int.fromEnvironment, which is an external const factory constructor. You can read that as it being "magic".)
Similarly, the String class does not have an unnamed constructor taking zero or one arguments, so you can't write String() or String('Ahmed'). Not because it's invalid syntax, it's just trying to call a constructor which does't exist.
The String class has String.fromCharCode/String.fromCharCodes as constructors that you can use.
You seem to be assuming that because something, X, is a class, you can write X() or X(someXValue). That's just not true in Dart. You have to look at each class to see which constructors it actually has.
I have the following Scala enum which I designed after reading this answer:
object RunMode extends Enumeration {
val CLIENT_MODE = Value("CLIENT_MODE")
val SERVER_MODE = Value("SERVER_MODE")
}
I am now trying to pass an instance of it as an argument into the constructor of another class:
package com.me.myapp.shared.config
import com.me.myapp.shared.utils.RunMode
class MyAppConfig(runMode : RunMode) {
}
This gives me a compiler error:
Cannot resolve symbol RunMode
BTW: com.me.myapp.shared.utils.RunMode is the correct package path for RunMode, so that's not the issue here!
I assume that this is maybe because there is only (ever) one single instance of the RunMode object, and perhaps that prevents it from being passed in as an arg.
Either way, I don't really care what the solution is. But I need an "enum" called RunMode and I'll need to be able to pass instances of it into contructors of other classes. Any ideas?
You are almost there, the correct type for a value of an Enumeration is Enumeration.Value, so here you need to use:
class MyAppConfig(runMode : RunMode.Value) {
}
You're correct in the assumption that the only instance that inhabits the type RunMode is the object itself.
However fixing your problem isn't all that difficult.
object RunMode extends Enumeration {
type RunMode = Value
val CLIENT_MODE = Value("CLIENT_MODE")
val SERVER_MODE = Value("SERVER_MODE")
}
The Enumeration class gives you the type Value which is the type that all of your enumerated types should have. It's scoped to the class instance, so every instance of Enumeration get's its own Value type.
You can give it a proper name by creating a type alias.
Then you can import the inner type alias like this:
import com.me.myapp.shared.utils.RunMode._
And then you can pass Instances of your Enumeration around, therefore also allowing you to keep the MyAppConfig the same as it is right now.
Alternatively, you could of course also omit the type alias and just change the type signature of MyAppConfig to RunMode.Value. However I believe the former method is much better at clarifying intent.
class MyAppConfig(runMode: RunMode.Value) {
}
... and supply it with all necessary arguments even if they where not required for the auxiliary constructor. (Source: http://joelabrahamsson.com/learning-scala-part-four-classes-and-constructors/) This is not the case in Java. What is the reasoning behind that?
In Scala, the primary constructor's parameters are available anywhere inside the class (among other reasons, so you don't have to repeat Java's this.x = x; this.y = y; this.z = z;). If the parameter isn't used, it has no reason to be a parameter in the first place, so consider only the case where it is used. So if you could avoid supplying these parameters, and then got to the place where they are used, what should happen?
The compiler could use default values (null/0/false/etc), which is very likely not what the user wants. Or throw an exception, turning a compilation error into a runtime error, which is the opposite of what we want.
Easy: if a parameter is not required, don't add it to the main constructor.
In java, all constructors also execute the code in the body of the class:
public class Foo {
String x = mkX();
public Foo() { System.out.println("THIS"); }
public static String mkX() { System.out.println("THAT"); return "";}
}
new Foo(); // prints THAT, then THIS
The requirement in scala is actually more relaxed: your main constructor is allowed to have arguments.
I've run into an issue where, when using a loop and passing an object into a method, my object is being modified when the method returns, breaking the next iteration.
The code I'm using is quite elaborate, so I'll simplify with the following:
val car: Car = expensiveMethod("greenCar")
for (i <- 1 to 5) {
foo(car)
}
def foo (car: Car) = {
assert(car.name == "greenCar")
car.name = "redCar"
}
expensiveMethod is, as it sounds, expensive, so I'd prefer not to call it inside the for loop every time.
Car is also not a case class, so I can't use the built in copy method.
Is there a simple way to send a copy of car into foo, or an alternate approach?
It may be that name member of your Car class is public and mutable.
Also from definition of foo function the signature is foo: (car: Car)Unit, which could mean that it is not a pure function, a side effecting function (or procedure) in this case as its modifying the parameter. You should explicitly create a copy of parameter and mutate the copy.
I am new to scala, just doing some practice;
I tried a very simple program, briefed as following:
abstract class Device(val cds: Array[Char]) {
var codes = Array[Char](cds: _*)
def encrpt(code: Char): Char
var nextDevice: Device
def setNext(next: Device):Unit = {
nextDevice = next
}
}
//compiler error shows here
class Input(codes: Array[Char]) extends Device(codes) {
override def encrpt(code: Char) = code
}
you could see there is a compiler error at line 21, following is the message:
class Input needs to be abstract, since variable nextDevice in class Device of type com.me.acm.problem1009.Device is not
defined (Note that variables need to be initialized to be defined)
I am pretty confusing that error, my understanding, define some variable and an setter method in the parent class, so the child classes can use it without define it again. it is straight forward.
I guess I missed something. Could someone explain it to me and tell what is the correct way? thanks.
In Scala, variables do not have assumed default values as they do in Java (or many other languages). Thus, when you declare a variable, you must always specify its initial value.
In your code, you declare a variable nextDevice, but you do not give it a value. Since Scala always needs a value, it interprets what you've written as nextDevice being an abstract field, so the compiler is telling you that it must be overridden.
If you change that line to the following, for example, to specify an initial value, then the error will disappear:
var nextDevice: Device = new Input(Array())
As the error message is telling you, the variable nextDevice needs to be initialized in the constructor on Input.
class Input(codes: Array[Char]) extends Device(codes) {
override def encrpt(code: Char) = code
nextDevice = null
}
Note that using null is frowned upon in Scala. You should probably change the type of your variable to Option[Device]