Can I add class fields dynamically using macros? - scala

I'm new to Scala macros, so sorry if this is an obvious question.
I wonder if the following is even possible before I dig in deeper.
Let's say I have a class named DynamicProperties
Is it possible to add members to the class based on something like this?
val x: DynamicProperties = ...
x.addProperty("foo", 1)
x.addProperty("bar", true)
x.addProperty("baz", "yep")
and have it be translated somehow to a class that looks like this more or less?
class SomeName extends DynamicProperties {
val foo: Int = 1
val bar: Boolean = true
val baz: String: yep
}
I guess this can be done via reflection, but I want people who use this, to have auto complete when they type x. that will fit what they did earlier using the addProperty method. Is this possible using Scala marcos? I want to try to implement it, but it will be good to know if this is going down a dead end path or not.

Related

HList(DValue[A], DValue[B]) to HList(A, B) at library level?

I'm building a data binding library, which has 3 fundamental classes
trait DValue[+T] {
def get:T
}
class DField[T] extends DValue[T] {
// allow writes + notifying observers
}
class DFunction[T](deps:DValue[_]*)(compute :=> T) extends DValue[T] {
def get = compute // internally compute will use values in deps
}
However, in this approach, the definition of DFunction is not quite robust - it requires the user of DFunction to make sure all DValues used in compute are put into the 'deps' list. So I want the user to be able to do something like this:
val dvCount:DValue[Int] = DField(3)
val dvElement:DValue[String] = DField("Hello")
val myFunction = DFunction(dvCount, dvElement) { (count, element) => // compiler knows their type
Range(count).map(_ => element).toSeq
}
As you can see when I'm constructing 'myFunction', the referenced fields and the usage is clearly mapped.
I feel maybe HList would allow me to provide something at library level that'd allow this, but I cannot figure out how, would this be possible with HList? or there's something else that'd help achieve this?
shapeless.ops.hlist.Mapper allows you to do this with a Poly function.
Unfortunately the documentation on it isn't great; you might need to do some source diving to see how to use it

Generic class wrapper in scala

Hello I would like to create a generic wrapper in scala in order to track the changes of the value of any type. I don't know/haven't found any other ways so far and I was thinking of creating a class and I've been trying to use the Dynamic but it has some limitations.
case class Wrapper[T](value: T) extends Dynamic {
private val valueClass = value.getClass
def applyDynamic(id: String)(parameters: Any*) = {
val objectParameters = parameters map (x => x.asInstanceOf[Object])
val parameterClasses = objectParameters map (_.getClass)
val method = valueClass.getMethod(id, parameterClasses:_*)
val res = method.invoke(value, objectParameters:_*)
// TODO: Logic that will eventually create some kind of event about the method invoked.
new Wrapper(res)
}
}
With this code I have trouble when invoking the plus("+") method on two Integers and I don't understand why. Isn't there a "+" method in the Int class? The error I am getting when I try addition with both a type of Wrapper/Int is:
var wrapped1 = Wrapper(1)
wrapped1 = wrapped1 + Wrapper[2] // or just 2
type mismatch;
found : Wrapper[Int]/Int
required: String
Why is it expecting a string?
If possible it would also be nice to be able to work with both the Wrapper[T] and the T methods seamlessly, e.g.
val a = Wrapper[Int](1)
val b = Wrapper[Int](2)
val c = 3
a + b // Wrapper[Int].+(Wrapper[Int])
a + c // Wrapper[Int].+(Int)
c + a // Int.+(Wrapper[Int])
Well, if youre trying to make a proxy which will get any changes of desired values you'l probably fail without agents(https://dzone.com/articles/java-agent-1) because it will force you make code modifications for bytecode that accepts final classes and primitives to accept your proxy instead of that and it would require more than intercepting changes of "just class" but also all classes of members and produce origin-of-value analysis and so on. It's by no way trivial problem.
Another approach is to produce diffs of case classes by comparing classes in certain points of execution and there's generic implementation like that, it uses derivation for computing diffs: https://github.com/ivan71kmayshan27/ShapelesDerivationExample I believe you can came with easier solution with magnolia. Actualy this one is unable to work for just classes unless you write your own macro and have some problems regarding ordered and unordered collections.

Scala var best practice - Encapsulation

I'm trying to understand what's the best practice for using vars in scala, for example
class Rectangle() {
var x:Int = 0
}
Or something like:
class Rectangle() {
private var _x:Int = 0
def x:Int = _x
def x_(newX:Int):Unit = _x=newX
}
Which one can be considered as better? and why?
Thank you!
As Luis already explained in the comment, vars are something that should be avoided whenever you are able to avoid it, and such a simple case like you gave is one of those that can be better designed using something like this:
// Companion object is not necessary in your case
object Rectangle {
def fromInt(x: Int): Option[Rectangle] = {
if(x > 0) {
Some(Rectangle(x))
} else None
}
final case class Rectangle(x: Int)
It would be very rare situations when you can't avoid using vars in scala. Scala general idiom is: "Make your variables immutable, unless there is a good reason not to"
I'm trying to understand what's the best practice for using vars in scala, […]
Best practice is to not use vars at all.
Which one can be considered as better? and why?
The second one is basically equivalent to what the compiler would generate for the first one anyway, so it doesn't really make sense to use the second one.
It would make sense if you wanted to give different accessibility to the setter and the getter, something like this:
class Rectangle {
private[this] var _x = 0
def x = _x
private def x_=(x: Int) = _x = x
}
As you can see, I am using different accessibility for the setter and the getter, so it makes sense to write them out explicitly. Otherwise, just let the compiler generate them.
Note: I made a few other changes to the code:
I changed the visibility of the _x backing field to private[this].
I changed the name of the setter to x_=. This is the standard naming for setters, and it has the added advantage that it allows you to use someRectangle.x = 42 syntactic sugar to call it, making it indistinguishable from a field.
I added some whitespace to give the code room to breathe.
I removed some return type annotations. (This one is controversial.) The community standard is to always annotate your return types in public interfaces, but in my opinion, you can leave them out if they are trivial. It doesn't really take much mental effort to figure out that 0 has type Int.
Note that your first version can also be simplified:
class Rectangle(var x: Int = 0)
However, as mentioned in other answers, you really should make your objects immutable. It is easy to create a simple immutable data object with all the convenience functions generated automatically for you by using a case class:
final case class Rectangle(x: Int = 0)
If you now want to "change" your rectangle, you instead create a new one which has all the properties the same except x (in this case, x is the only property, but there could be more). To do this, Scala generates a nifty copy method for you:
val smallRectangle = Rectangle(3)
val enlargedRectangle = smallRectangle.copy(x = 10)

Using a Lens on a non-case class extending something with a constructor in Scala

I am probably thinking about this the wrong way, but I am having trouble in Scala to use lenses on classes extending something with a constructor.
class A(c: Config) extends B(c) {
val x: String = doSomeProcessing(c, y) // y comes from B
}
I am trying to create a Lens to mutate this class, but am having trouble doing so. Here is what I would like to be able to do:
val l = Lens(
get = (_: A).x,
set = (c: A, xx: String) => c.copy(x = xx) // doesn't work because not a case class
)
I think it all boils down to finding a good way to mutate this class.
What are my options to achieve something like that? I was thinking about this in 2 ways:
Move the initialization logic into a companion A object into a def apply(c: Config), and change the A class to be a case class that gets created from the companion object. Unfortunately I can't extend from B(c) in my object because I only have access to c in its apply method.
Make x a var. Then in the Lens.set just A.clone then set the value of x then return the cloned instance. This would probably work but seems pretty ugly, not to mention changing this to a var might raise a few eyebrows.
Use some reflection magic to do the copy. Not really a fan of this approach if I can avoid it.
What do you think? Am I thinking about this really the wrong way, or is there an easy solution to this problem?
This depends on what you expect your Lens to do. A Lens laws specify that the setter should replace the value that the getter would get, while keeping everything else unchanged. It is unclear what is meant by everything else here.
Do you wish to have the constructor for B called when setting? Do you which the doSomeProcessing method called?
If all your methods are purely functional, then you may consider that the class A has two "fields", c: Config and x: String, so you might as well replace it with a case class with those fields. However, this will cause a problem while trying to implement the constructor with only c as parameter.
What I would consider is doing the following:
class A(val c: Config) extends B(c) {
val x = doSomeProcessing(c, y)
def copy(newX: String) = new A(c) { override val x = newX }
}
The Lens you wrote is now perfectly valid (except for the named parameter in the copy method).
Be careful if you have other properties in A which depend on x, this might create an instance with unexpected values for these.
If you do not wish c to be a property of class A, then you won't be able to clone it, or to rebuild an instance without giving a Config to your builder, which Lenses builder cannot have, so it seems your goal would be unachievable.

Trouble with constructors in Scala

It's been a while since I've used constructors at all- so naturally when I have to use one in Scala I'm having trouble.
I want to do the following: When I create a new class without passing through anything- it creates an empty vector.
Otherwise if it passes through a vector- we use that vector and define it to be used with the class.
How do I do this? I previously had
Class example{
val a: Vector[int] = Vector();
Then I'm lost. I was thinking of doing something like
Class example{
val a: Vector[Int] = Vector()
def this(vector: Vector[Int]){
this{
a = vector
}
}
But I'm getting tons of errors. Can anyone help? I'm trying to find my scala book but I can't find it- I know it had a good section on constructors.
Sounds like you want a constructor with a default argument:
class example(val a : Vector[Int] = Vector())
If you really want to do this by constructor overloading, it looks like this:
class Example(val a: Vector[Int]) {
def this() = this(Vector())
}
Personal-opinion addendum: Overloading and default arguments are often good to avoid. I'd recommend just making a different function that calls the constructor:
class Example(val a: Vector[Int])
object Example {
def empty = new Example(Vector())
}
case class Example(a: Vector[Int] = Vector())
No need to put the val keyword.
Also, using the case keywork you get:
a compact initialisation syntax: Example(Vector(1,2)), instead of new Example(Vector(1,2))
pattern matching for you class
equality comparisons implicitly defined and pretty toString
Reference