Suppose I have a complicated class with a lot of inputs. This class is not a dataclass class. Further, if I import it explicitly, I would like it to complain if I do not provide all of the arguments.
However, for interfacing purposes and clean code, I would like to define default values for the constructors and pass around arguments for the complex class as, more or less, a 'defined' dict.
This is a good task for the dataclass, and I have defined a dataclass class containing all the arguments with defaults, and which I modify and manipulate.
#dataclass
ComplicatedClassArgs:
arg1: int
arg2: bool = False
...
My question amounts to: can I write the following, and expect and/or tell the dataclass to call super.init(...) with all the named attributes I have defined?
#dataclass
ComplicatedClassArgs(ComplicatedClass):
arg1: int
arg2: bool = False
def some_meta_arg_manipulation_function(...):
pass
def some_other_arg_related_function(...):
pass
Such that I know I have composed a more advanced inner class behavior with a dataclass entry point?
I might have misunderstood your use case, but it looks to me like inheritance is the wrong tool for the job here. How about a simple #classmethod?
#dataclass
ComplicatedClassArgs:
arg1: int
arg2: bool
#classmethod
def from_dict(cls, kwargs=None):
""""ComplicatedClassArgs factory.
This method provides sensible default values that
may or may not be replaced through the input kwargs.
"""
if kwargs is None:
kwargs = {}
default_params = {
'arg1': 1,
'arg2': False
}
return cls(**{**default_params, **kwargs})
>>> ComplicatedClassArgs()
Traceback (most recent call last):
...
TypeError: __init__() missing .. required positional arguments
>>> ComplicatedClassArgs.from_dict()
ComplicatedClassArgs(arg1=1, arg2=False)
Related
Here's a stripped down, minimal version of the class causing the problem:
import scala.reflect.runtime.universe._
import scala.reflect.ClassTag
final case class Template[InnerType]()(implicit innerTypeTag: TypeTag[InnerType], innerClassTag: ClassTag[InnerType]) {
def get(name: String, session: Session) =
session(name).as[InnerType]
}
and usage that produces the exception:
.exec(session => session.set("d", 2.0)) // this stores value 2.0 in a Gatling session variable called 'd'
.exec{ session =>
val foo = new Template[Double]()
println(session("d").as[Double]) // this retrieves 'd' correctly, printing 2.0
println(session("d").as[java.lang.Double]) // this retrieves 'd' correctly, printing 2.0
println(foo.get("d", session)) // this triggers an error: j.l.ClassCastException: Can't cast attribute 'd' '2.0' of type class java.lang.Double into double'
session
}
Why is there a difference between session("d").as[Double] and session("d").as[InnerType] if InnerType is Double? How can I fix this?
Best I can tell, it's taking the primitive type and converting it to the boxed version, but I haven't been able to find a way to reverse this, i.e. .as[InnerType.primitive]
The work-around I've come up with is a bit of a pain, as it requires this for all primitives:
if (typeTag[InnerType].tpe <:< typeTag[Double].tpe)
session(variableName).as[Double].asInstanceOf[InnerType]
else if (typeTag[InnerType].tpe <:< typeTag[Int].tpe)
session(variableName).as[Int].asInstanceOf[InnerType]
...
else
session(variableName).as[InnerType]
In your function, you take two implicit arguments. innerTypeTag: TypeTag[InnerType], innerClassTag: ClassTag[InnerType].
In the function body, you call .as[InnerType], which requires the implicit argument TypeCaster[InnerType].
The TypeCaster implicitly supplied to .as by your function is "derived" from the function genericTypeCaster.
Explicitly supplying the arguments, the body of your get method looks like this:
session(name).as[InnerType](
TypeCaster.genericTypeCaster(innerClassTag),
... // other implicit parameters
)
The genericTypeCaster does not know about Double and java.lang.Double and just act according to the class tag, so that's why your code fails.
If you call .as[Double] directly, the implicit argument needed is TypeCaster[Double]. Because there is a DoubleCaster of this exact type, it is picked over the generic (and dumber) one.
In other words, session("d").as[Double] looks like this, explicitly.
session("d").as[Double](
TypeCaster.DoubleCaster,
... // other implicit parameters
)
This caster knows both Double and java.lang.Double, and also parses double values from strings.
If you understand the difference between the two caster, fixing is easy:
final case class Template[InnerType]()(implicit innerClassTag: ClassTag[InnerType], innerTypeCaster: TypeCaster[InnerType]) {
def get(name: String, session: Session) =
session(name).as[InnerType]
}
So when you create val foo = new Template[Double](), foo will use the more powerful DoubleCaster.
I m trying to declare function in trait that takes variable number of argument and during implementation of the trait I would expand the number of arguments. How can this done in Scala
I am expecting to come up with code like below.
trait Column {
def rule
}
case object FirstColumn extends Column{
def rule(s: String) : String
}
case object SecondColumn extends Column{
def rule(s1: String, s2: String) : String
}
I have tried using Strings* , but it is not allowing me to expand my number of arguments during implementation. I understand there are various way to handle this problem but i am specifically looking to have above signature for my team to write functions.
This is primarily expanding on my comment on the question. This answer gets you about as close as Scala lets you get to what you want, but it also shows why it's probably not a good idea to do what you're doing.
You can express (something close to) the type you want, but I'm not sure what you intend to gain. First, if you want to take different arglist types, then Column needs to be generic.
trait Column[-A] {
def rule(arg: A): String
}
Then we can implement your case objects as subclasses of an appropriate parameterization of this.
case object FirstColumn extends Column[String] {
def rule(arg: String): String =
"stub implementation"
}
case object SecondColumn extends Column[(String, String)] {
def rule(arg: (String, String)): String =
"stub implementation"
}
Note that FirstColumn and SecondColumn do not inherit from the same Column[A] as they don't implement the same method. We can get them to have a common type, but... not in a very useful way.
One option is to find a common supertype of Column[String] and Column[(String, String)], which (since the argument is contravariant) is akin to finding a common subtype of String and (String, String). The closest common subtype is... Null. That's not helpful unless you're only ever planning to pass null to your rule.
Instead, we can use existentials.
val foo: Column[_] = FirstColumn
val bar: Column[_] = SecondColumn
Now we've lost all type information. You can access the foo.rule slot and you can print it, but you can't call it because we don't know what we need to pass it. You'll have to do a cast to get it back to a usable format.
The point that I'm making here is that, yes, it's doable, but once you've lost as much type information as you're giving up, there's not much point. The type system is correctly telling us that foo and bar have virtually nothing in common except the existence of a method named rule which takes... some kind of argument. From a type theory perspective, it's hard to get more uninteresting than that.
I was receiving this error in my Hadoop job.
java.lang.NoSuchMethodException: <PackageName>.<ClassName>.<init>(<parameters>)
In most Scala code, you would have it in compile time. But since this job is called in runtime I was not catching it in compile time.
I would think default parameter would cause constructors with both signatures to be created, one taking a single argument.
class BasicDynamicBlocker(args: Args, evaluation: Boolean = false) extends Job(args) with HiveAccess {
//I NEEDED THIS TOO:
def this(args: Args) = {
this(args, false)
}
...
}
I learned the hard way that I needed to declare the overloaded constructor using this. (I wanted to write this out in case it helps someone else.)
I also have a small questions. It still seems redundant to me. Is there a reason Scala language's design restrictions require this?
It is not like when you have default parameter you will get overloads generated for each possible case, like for example:
def method(num: Int = 4, str: String = "") = ???
you expect compiler to generate
def method(num: Int) = method(num, "")
def method(str: String) = method(4, str)
def method() = method(4, "")
but that is not the case.
You will instead have generated methods (in companion object), for each default param
def method$default$1: Int = 4
def method$default$2: String = "a"
and whenever you say in your code
method(str = "a")
it will be just changed to
method(method$default$1, "a")
So in your case, constructor with signature this(args: Args) just did not exist, there was only the 2 param version.
You can read more here: http://docs.scala-lang.org/sips/completed/named-and-default-arguments.html
In Scala I would like to have something like this
TokenizerExample.scala
class TokenizerExample private (whateva : Any)(implicit val separator : Char = '.') {
def this(data2Tokenize : String)(implicit s : Char) {
this("", s) //call to base constructor
}
def this(data2Tokenize : Array[Char])(implicit s : Char) { {
this("", s) //call to base constructor
}
}
what I would like to achieve is to allow the user to call any of the two public constructors either providing or not the separator, but if they do NOT provide the separator automatically take the one in the base constructor, I was wondering if there is a value that I can pass to the base constructor so that scala use the default on the private base constructor.
what I would like to avoid it to do the next in each constructor
def this(_3rdConstructor : SytringBuilder)(implicit s : Char = '.') ...
I tried this in many different ways, with the values being implicit, with the separator as a Option, but I do not get a result that I actually like, specially because scala complains about having implicit values in multiple constructors (which kind of defeats the purpose of having them). Is there a way to achieve that behavior in a nice way without
1) forcing the user to provide a separator.
2) go into "bad-practices" by passing null values and then validating them (specially because that would not allow my separator to be a val in the constructor.
3) creating YET ANOTHER LANGUAGE just because I dislike a small little thing about one of them :) .
I would strongly advice you against using implicits for this purpose. The resolution rules are rather complex, and it makes the code extremely hard to follow, because it is almost impossible to tell what value the constructor will end up receiving without the debugger.
If all you are trying to do is avoid defining the default in multiple places, just define it in a companion object:
object Foo {
val defaultParam = ','
}
class Foo {
import Foo.defaultParam
def this(data: String, param: Char = defaultParam) = ???
def this(data: List[Char], param: Char = defaultParam) = ???
// etc ...
}
If you insist on using implicits, you can use a similar approach to the above: just make defaultParam definition implicit, drop the defaults, replacing them with implicit lists, and then import Foo._ in scope where you are making the call. But, really, don't do that: it adds no value, and only has disadvantages in this case.
I'm writing a message parser. Suppose I have a superclass Message with two auxiliary constructors, one that accepts String raw messages and one that accepts a Map with datafields mapped out in key-value pairs.
class Message {
def this(s: String)
def this(m: Map[String, String])
def toRaw = { ... } # call third party lib to return the generated msg
def map # call third party lib to return the parsed message
def something1 # something common for all messages which would be overriden in child classes
def something2 # something common for all messages which would be overriden in child classes
...
}
There's good reason to do this as the library that does parsing/generating is kind of awkward and removing the complexity of interfacing with it into a separate class makes sense, the child class would look something like this:
class SomeMessage extends Message {
def something1 # ...
def something2 # ...
}
and the idea is to use the overloaded constructors in the child class, for example:
val msg = new SomeMessage(rawMessage) # or
val msg = new SomeMessage("fld1" -> ".....", "fld2" -> "....")
# and then be able to call
msg.something1
msg.something2 # ...
However, the way auxiliary constructors and inheritance seem to behave in Scala this pattern has proven to be pretty challenging, and the simplest solution I found so far is to create a method called constructMe, which does the work of the constructors in the above case:
val msg = new SomeMessage
msg.constructMe(rawMessage) # or
msg.constructMe("fld1" -> ".....", "fld2" -> "....")
which seems crazy to need a method called constructMe.
So, the question:
is there a way to structure the code so to simply use the overloaded constructors from the superclass? For example:
val msg = new SomeMessage(rawMessage) # or
val msg = new SomeMessage("fld1" -> ".....", "fld2" -> "....")
or am I simply approaching the problem the wrong way?
Unless I'm missing something, you are calling the constructor like this:
val msg = new SomeMessage(rawMessage)
But the Message class doesn't not take a parameter, your class should be defined so:
class Message(val message: String) {
def this(m: Map[String, String]) = this("some value from mapping")
}
Also note that the constructor in scala must call the primary constructor as first action, see this question for more info.
And then the class extending the Message class should be like this:
class SomeMessage(val someString: String) extends Message(someString) {
def this(m: Map[String, String]) = this("this is a SomeMessage")
}
Note that the constructor needs a code block otherwise your code won't compile, you can't have a definition like def this(someString: String) without providing the implementation.
Edit:
To be honest I don't quite get why you want to use Maps in your architecture, your class main point it to contain a String, having to do with complex types in constructors can lead to problems. Let's say you have some class which can take a Map[String, String] as a constructor parameter, what will you do with it? As I said a constructor must call himself as first instruction, what you could is something like this:
class A(someString: String) = {
def this(map: Map[String, String]) = this(map.toString)
}
And that's it, the restrictions in scala don't allow you to do anything more, you would want to do some validation, for example let's say you want to take always the second element in the map, this could throw exceptions since the user is not forced to provide a map with more than one value, he's not even forced to provide a filled map unless you start filling your class with requires.
In your case I probably would leave String as class parameter or maybe a List[String] where you can call mkString or toString.
Anyway if you are satisfied calling map.toString you have to give both constructor implementation to parent and child class, this is one of scala constructor restrictions (in Java you could approach the problem in a different way), I hope somebody will prove me wrong, but as far as I know there's no other way to do it.
As a side note, I personally find this kind of restriction to be correct (most of the time) since the force you to structure your code to be more rigorous and have a better architecture, think about the fact that allowing people to do whatever they want in a constructor (like in java) obfuscate their true purpose, that is return a new instance of a class.