I have a situation, where in Kotlin I want to take the name of a reference, modify it, and then call a function with the object, which corresponds with the modified name. For example:
val a = "Foo"
val aAlt = "Bar"
fun doSomething(s: String){
println(s.*addAltToStringName()* )
}
So that by calling
doSomething(a)
the result is
Bar
I know, that doing something "untyped-scripty" like this in an object oriented language is dangerous, but I have other checks to prevent Nullpointers etc.
Thanks!
This can be done with reflection, but only if the argument to the function is property reference, so you can get its name. The String object itself would provide no way to retrieve info about whatever variables might hold references to it. In other words, your property a references a String object, but that String object itself has no name or knowledge of the property that references it.
class Test {
val a = "Foo"
val aAlt = "Bar"
fun doSomething(s: KProperty<*>){
val propertyName = s.name + "Alt"
val propertyValue = Test::class.memberProperties.find { it.name == propertyName }?.get(this)
println(propertyValue)
}
}
fun main() {
val test = Test()
test.doSomething(test::a)
}
Related
It seems like having uninitialized members in the object body is forbidden in Scala objects..
I wanted to do something like (if it was in Java)
class MyClass {
private String str;
private String reassignString(String value) {
str = value;
}
I'm restricted on changing this code from object to class (since this repo is used by many teams) - what's a good Scala way to handle this kind of situation? Sorry the question is really vague.
Here is another bad idea:
object Lazy {
lazy val v = if (underlying ne null) underlying else ???
var underlying: String = null
}
Try(Lazy.v)
Lazy.underlying = "yes"
Try(Lazy.v)
Lazy.underlying = null
Try(Lazy.v)
The point is that the lazy val gets more than one shot at initialization, but is successfully initialized only once, if that's what you want.
Note that default initializer syntax is on its way out. They want you to write null if you want null.
My preferred default initializer:
var underlying: String = underlying
just to break the ice at dinner parties.
Uninitalized values are a bad idea, so str needs to be initialised to a valid value.
There are three obvious options:
Give str the default value
private var str: String = _
Pick you own default
private var str: String = "undefined"
Use Option
class MyClass {
private var str: Option[String] = None
private def reassignString(value: String): Unit = {
str = Some(value)
}
}
str in this Java code is initialized, to null. Scala simply requires you to make it explicit whether that's what you want.
scala.Enumerator.nextName and .nextNameOrNull currently read:
/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
nextNameOrNull is subsequently called to get the name to use for the item being created in the Enumeration.
How does this code actually achieve this?
When I copy-paste it into a simple example:
class MyBaseClass extends Serializable {
/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
protected final def Value(): Val = Val(nextNameOrNull)
case class Val(name:String)
}
object MyObject extends MyBaseClass {
val myValue = Value
println("Hello from MyObject, myValue: " + myValue)
}
it prints: Hello from MyObject, myValue: Val(null) instead of the hoped for Val(myValue)
What do I need to add to make it work?
In Scala JVM, Enumeration uses reflection to get the name of the val to which a Value was assigned to if nextNameOrNull returns null.
In Scala.js, we do not have this luxury (no reflection support). Therefore, the Scala.js compiler special cases scala.Enumeration, so that code that uses it can work.
If you want to implement some method that knows the name of the val it is assigned to, have a look at sbt's project macro. Scala's Enumerations could have been implemented that way starting 2.10, but are older.
nextNameOrNull isn't not working anymore even for original Scala - as passing a sequence of names to constructor is deprecated and removed.
Here is the execution for 2.11.2 using original scala's Enumeration (not the replaced one from scala-js):
scala> object MyObject extends Enumeration {
| val MyValue1, MyValue2 = Value
|
| println("nextName: " + nextName)
| }
defined object MyObject
scala> MyObject
nextName: null //still null
In 2.10.x nextName used inside one of constructor to specify names explicitly as sequence (which is removed in 2.11.x):
#deprecated("Names should be specified individually or discovered via reflection", "2.10.0")
def this(initial: Int, names: String*) = {
this(initial)
this.nextName = names.iterator
}
}
Now this constructor is removed and nextName is just a dead code. Scala uses populateNameMap() to provide names for nameOf (if they're not specified:
private def populateNameMap() {
val fields = getClass.getDeclaredFields
def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
// The list of possible Value methods: 0-args which return a conforming type
val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
classOf[Value].isAssignableFrom(m.getReturnType) &&
m.getDeclaringClass != classOf[Enumeration] &&
isValDef(m))
methods foreach { m =>
val name = m.getName
// invoke method to obtain actual `Value` instance
val value = m.invoke(this).asInstanceOf[Value]
// verify that outer points to the correct Enumeration: ticket #3616.
if (value.outerEnum eq thisenum) {
val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
nmap += ((id, name))
}
}
}
So it uses reflection by default. You can explicitly specify the name for every value as it's described here.
I think same for ScalaJs, excluding that it has no populateNameMap() method as there is no such kind of reflection for JavaScript - so result for non-explicitly named parameters is:
override def toString() =
if (name != null) name //only if you did `Value("explicitName")` somwhere inside enumeration
// Scala.js specific
else s"<Unknown name for enum field #$i of class ${getClass}>"
But again, nextNameOrNull is dead in both Scala and Scala-Js - it always returns null.
I'm searching for quite a while to get around the following problem:
Every instance of my class "B" uses a method to store a Seq "output" in a file.
class B extends IO {
private var b = 0.0
var output = Seq(0.0)
def add(a:Int) = {
b += a
output :+= b
WriteToFile(fileName, output)
}
}
And theres also a trait where the WriteToFile-method is:
trait IO {
def WriteToFile(fileName:String, data:Seq[Int]) = {
create file and name it something like: fileName+this+".m"
}
}
So every time the method "add" is called on an instance on class "B", the output-sequence is stored in a file. I want to create a different file for every instance of class "B". But when I create an instance like
val x = new B
the this-keyword in the WriteToFile-Method just adds "Bank()" to the fileName. So, how can alter the code in such a way that every new instance of class "B" creates its own file? And how can I alter the WriteToFile-Method in such way that the name of the instance (here "x") is added to the String determining the fileName?
I'd discourage you from trying naming object instances according to the names of your variables. Variables are very different from references. For example, let's have this piece of code:
def foo: Object = {
val x = new Object;
val y = x;
return x;
}
This method creates some new Object. The reference to the object is assigned to variable x and then to variable y. So now we have one objects, but referenced by two variables. And when the method returns, the object still exists, but perhaps with variable referencing it.
So naming the object by a variable that's holding it isn't very meaningful - there can be multiple such variables, or none, and it changes during the lifetime of the object.
Instead, I'd suggest you to create your own mechanism for generating names. One possibility is to use an atomic counter (so that it can be safely used from multiple threads):
trait AtomicName {
val name = "prefix" + AtomicName.newId;
}
object AtomicName extends App {
import java.util.concurrent.atomic.AtomicInteger;
private val counter = new AtomicInteger(0);
protected def newId = counter.getAndIncrement;
}
Now everything extending AtomicName will have a unique name.
trait IO {
def myName =
this.getClass.getName.split("\\$",-1).dropRight(1).lastOption.getOrElse("")
}
class B extends IO {
var output = Seq(0.0)
}
object x extends B {
def test { println(myName + " has " + output) }
}
Note that you must use object x instead of val x, and this does contain some overhead, plus it is lazy--x gets created the first time its contents are used, not the first time it's stated. (If you call myName on something that is not an object, it will give you an empty string.)
I think this is a bad idea, but this is how to do it.
Is it possible to do this? (I'm using scala 2.10) To call a method that requires that the object has a function named "fullName", but the object being built with the Dynamic trait. The compiler complains, but maybe I'm doing it wrong.
I don't need this for any job, I'm just learning the language.
import scala.language.dynamics
object Main extends App {
class MyStatic {
private var privateName = ""
var lastName = ""
def name_= (n: String) {
privateName = n
}
def name = s"***$privateName***"
def fullName = s"$name $lastName"
}
class MyDynamic extends scala.Dynamic {
val map = collection.mutable.Map[String, String]()
def selectDynamic(key: String): String = map(key)
def updateDynamic(key: String)(value: String) {
map += key -> value
}
def applyDynamic(key: String)(value: Any*) = key match {
case "fullName" => {
val name = map("name")
val lastName = map("lastName")
s"$name $lastName"
}
}
}
def showFullName(o: { def fullName: String }) = s"My full name is $o.fullName"
println("Starting App...")
val s = new MyStatic
s.name = "Peter"
s.lastName = "Parker"
println(showFullName(s))
val d = new MyDynamic
d.name = "Bruce"
d.lastName = "Wayne"
println(showFullName(d))
}
The structural type { def fullName: String } basically means "any type with a no-arg method named fullName returning a String.
MyDynamic has no such method, and thus does not comply with this structural type. The fact that MyDynamic extends scala.Dynamic is irreleveant: it means that for any instance of it, you can perform what looks like a call to fullName, but it does not mean that MyDynamic (as a type) has any such member.
So the short answer is no, you cannot mix dynamic objects with structural typing like that.
For completeness, I must add that it could be made to work as you expected, but it would require a special provision from the compiler (namely, the compiler could consider than any type extending scala.Dynamic -- and implementing the required lookup methods -- is compatible with any structural typing, and implement the call not via reflection as is normally done, but by calling the corresponding lookup method).
You are trying to glue together two completely different things. While structural typing is also sometimes compared to 'duck-typing', its feature is exactly the use of static type information (even if on the use site the byte code will call reflection). Per definition, your dynamic type does not have such static type information. So you will never be able to convince the Scala compiler that your dynamic type has a method that can be statically verified to exist.
The only workaround would be to allow any type in showFullName and use reflection to call fullName (again, I'm not sure if this plays out with a dynamic object).
On the other hand, Scala will let you do anything with dynamic types, handing the responsibility over to you:
def showFullName(o: Dynamic) = s"My full name is $o.fullName"
println(showFullName(d))
I have a scala class:
class Foo {
def this(st: String) {
var baz = List[String]()
var jaz = "one" + st
// more code logic
}
}
First above code does not compile. Secondly I want baz and jaz to be private variables local to the lone constructor above and not instance variables.
How to solve this problem?
It does not compile because the first thing that MUST happen in an auxiliary constructor is a call to the primary constructor. I don't understand the second question, since the variables you have declared already ARE private
Something like this is maybe what you are looking for?
class Foo(st: String) {
val myInstance = {
var baz = List[String]()
var jaz = "one" + st
jax + baz.mkString(":")
}
}
The body of your class is the constructor. If you want to have some temporary values, you can declare a block with just about anything you want; that block can return a value, and you can store that value in an instance variable, in this case myInstance.