How to pass by Value in Scala [duplicate] - java

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Can Scala call by reference?
(3 answers)
Closed 6 years ago.
I wrote this simple program ( I pass Map from String to Int to method as a parameter) and it seems that is passing it by reference. How do I make it pass by Value?
import scala.collection.immutable._
import scala.io.Source._
/**
* Created by Alex on 5/11/16.
*/
object ScalaPassByValue {
type Env = scala.collection.mutable.Map[String,Int]
def mt_env : Env = {
scala.collection.mutable.Map.empty[String,Int]
}
def extend_env (sym: String, v: Int, env: Env) : Env = {
if(env.contains(sym)) {
env(sym) = v
env}
else {
env += (sym -> v)
env}
}
def main(args: Array[String]): Unit = {
bar(mt_env)
}
def bar (env: Env) : Unit = {
println("In A")
extend_env("a", 666,env)
print_env(env)
bullshit2(env)
bullshit3(env)
}
def bar2 (env: Env) : Unit = {
println("In AB")
extend_env("b", 326,env)
print_env(env)
}
def bar3 (env: Env) : Unit = {
println("In AC")
extend_env("c", 954,env)
print_env(env)
}
def print_env(env: Env) : Unit = {
//println("Environment")
for ((k,v) <- env){
v match {
case value: Int => print("Arg: "+k+" = ")
print(value+"\n")
case _ =>
}
}
}
}
Ideally I want main method to pass empty map to method bar which would add a map from 'b' to 666, then call two method to add 'b' and 'c' respectively. At the end I want to get printed
In A
Arg: a = 666
In AB
Arg: a = 666
Arg: b = 326
In AC
Arg: a = 666
Arg: c = 954
but get this:
In A
Arg: a = 666
In AB
Arg: b = 326
Arg: a = 666
In AC
Arg: b = 326
Arg: a = 666
Arg: c = 954
How can I make Scala pass my Map by value so modification in call to bar2 doesn't modify original map

Related

Reflection to get default value of parameter

I am trying to use reflection to get all the optional fields in a class and their default values (if any). This is my attempt:
fun getOptionalFields(componentType: KClass<out Any>): Map<String, DefaultValueData> {
val cons = componentType.primaryConstructor
val constructorSetup = cons?.parameters
?.filterNot { it.isOptional }
?.associate { it to getValueForNonOptional(it) } ?: error("Something went wrong when choosing default val")
val constructorInst = (cons.callBy(constructorSetup)::class as KClass<Any>)
val conParams = (componentType.primaryConstructor?.parameters ?: emptyList())
.filter { p -> p.isOptional }
.associate { p ->
Pair(p.name ?: "",
DefaultValueData(
p.type,
// the below line crashes
constructorInst.memberProperties.first { m -> m.name == p.name }.get(constructorInst)
)
)
}
return conParams
}
The error: Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
I am a bit puzzled at what get() wants me to pass if not the instance to get the value from?
You are trying to get the value by providing a KClass instead of the actual instance.
This is a working solution based on your method signature and your code above:
data class Test(
val required: String,
val optional: Int = 7
)
val componentType = Test::class
val constructorInst = Test("required") // i skipped constructing the class via constructor
val conParams = (componentType.primaryConstructor?.parameters ?: emptyList())
.filter { p -> p.isOptional }
.associate { p ->
Pair(p.name ?: "",
Pair(
p.type,
componentType.memberProperties.first { m -> m.name == p.name }.get(constructorInst)
)
)
}
println(conParams) // <- OUTPUTS: {optional=(kotlin.Int, 7)}
Why have i removed this code?
val constructorSetup = cons?.parameters
?.filterNot { it.isOptional }
?.associate { it to getValueForNonOptional(it) } ?: error("Something went wrong when choosing default val")
val constructorInst = (cons.callBy(constructorSetup)::class as KClass<Any>)
The resulting object cons.callBy(constructorSetup) is unused because calling ::class on the expression rendered it useless. Additionally it is not required to perform the requested task in your question.
When updating your above code, result will look like
fun getOptionalFields(componentType: KClass<out Any>): Map<String, DefaultValueData> {
val cons = componentType.primaryConstructor
val constructorSetup = cons?.parameters
?.filterNot { it.isOptional }
?.associate { it to getValueForNonOptional(it) } ?: error("Something went wrong when choosing default val")
val constructorInst = cons.callBy(constructorSetup) // <- removed ::class and cast
val conParams = (componentType.primaryConstructor?.parameters ?: emptyList())
.filter { p -> p.isOptional }
.associate { p ->
val value = constructorInst::class.memberProperties.first { m -> m.name == p.name }.get(constructorInst) as KProperty1<out Any, out Any>
Pair(p.name ?: "",
DefaultValueData(
p.type,
value
)
)
}
return conParams
}

Alloy API throws a Null when executing alloy command

I have been using the Alloy API which can be written in Java. My goal is to compile Alloy model, display it visually, and narrow down the search for instances.
At this time, I need to command the source of the Alloy language, which may execute correctly or throw a NullPointerException, depending on the source. I have checked the contents of the API class in the eclipse debugger, but I cannot understand it properly.
The issue is: The debugger shows that TranslateAlloyToKodkod.execute_command occurs java.lang.NullPointerException.
According to the Alloy API documentation,
TranslateAlloyToKodkod.execute_command returns null if the user chose "save to FILE" as the SAT solver, and nonnull if the solver finishes the entire solving and is either satisfiable or unsatisfiable.
But I never changed execute options that "save to FILE" as the SAT solver. For your information, the solver, Alloy analyzer finishes the entire solving of following two sources.
Would you let me know how to fix the problem?
Here is the Java code I created, with some additions from the API example:
import java.io.File;
import edu.mit.csail.sdg.alloy4.A4Reporter;
import edu.mit.csail.sdg.alloy4.Err;
import edu.mit.csail.sdg.alloy4.ErrorWarning;
import edu.mit.csail.sdg.alloy4compiler.ast.Command;
import edu.mit.csail.sdg.alloy4compiler.ast.Module;
import edu.mit.csail.sdg.alloy4compiler.parser.CompUtil;
import edu.mit.csail.sdg.alloy4compiler.translator.A4Options;
import edu.mit.csail.sdg.alloy4compiler.translator.A4Solution;
import edu.mit.csail.sdg.alloy4compiler.translator.TranslateAlloyToKodkod;
import edu.mit.csail.sdg.alloy4viz.VizGUI;
public final class exportXML {
private static String outputfilepath;
public static void main(String[] args) throws Err {
VizGUI viz = null;
A4Reporter rep = new A4Reporter() {
#Override public void warning(ErrorWarning msg) {
System.out.print("Relevance Warning:\n"+(msg.toString().trim())+"\n\n");
System.out.flush();
}
};
String args_filename = args[0];
String[] path_split = args_filename.split("/");
int pos_fname = path_split.length -1;
String[] filename_split = path_split[pos_fname].split("\\.");
for ( int i=0; i<filename_split.length; i++ ) {
System.out.println(filename_split[i]);
}
String dir = "";
for ( int i = 0; i < path_split.length - 1; i++ ) {
dir = dir.concat(path_split[i]) + "/";
}
String out_fname = "Instance_of_" + filename_split[0];
outputfilepath = dir + out_fname;
File outdir = new File(outputfilepath);
outdir.mkdir();
for(String filename:args) {
System.out.println("=========== parse + typechecking: "+filename+" =============");
Module world = CompUtil.parseEverything_fromFile(rep, null, filename);
A4Options options = new A4Options();
options.solver = A4Options.SatSolver.SAT4J;
for (Command command: world.getAllCommands()) {
System.out.println("=========== command : "+command+" ============");
A4Solution ans = TranslateAlloyToKodkod.execute_command(rep, world.getAllReachableSigs(), command, options);
System.out.println(ans);
if (ans.satisfiable()) {
int cnt = 1;
A4Solution tmp = ans.next();
while ( tmp.satisfiable() ) {
tmp = tmp.next();
cnt++;
}
System.out.println("=========== "+cnt+" satisfiable solution found ============");
tmp = ans;
String[] outXml = new String[cnt];
for ( int i = 0; i < cnt; i++ ) {
outXml[i] = outputfilepath + "/" + out_fname + String.valueOf(i+1) + ".xml";
tmp.writeXML(outXml[i]);
tmp = tmp.next();
}
}
}
}
}
}
This is the sample of Alloy sources that will be successfully executed:
module adressBook
open ordering [Book]
abstract sig Target {}
sig Addr extends Target {}
abstract sig Name extends Target {}
sig Alias, Group extends Name {}
sig Book {
names: set Name,
addr: names -> some Target
}
{
no n: Name | n in n.^(addr)
all a: Alias | lone a.addr
}
pred add (b, b': Book, n: Name, t: Target) {
t in Addr or some lookup [b, t]
b'.addr = b.addr + n -> t
}
pred del (b, b': Book, n: Name, t: Target) {
no b.addr.n or some n.(b.addr) - t
b'.addr = b.addr - n -> t
}
fun lookup (b: Book, n: Name): set Addr {
n.^(b.addr) & Addr
}
pred init (b: Book) {no b.addr}
fact traces {
init [first]
all b: Book - last | let b' = next [b] |
some n: Name, t: Target | add [b, b', n, t] or del [b, b', n, t]
}
pred show {}
run show for 10
assert lookupYields {
all b: Book, n: b.names | some lookup [b, n]
}
check lookupYields for 3 but 4 Book
check lookupYields for 6
This is the Alloy source that will fail to execute (it will throw a null pointer):
sig Element {}
one sig Group {
elements: set Element,
unit: one elements,
mult: elements -> elements -> one elements,
inv: elements -> one elements
}
fact NoRedundantElements {
all e: Element | e in Group.elements
}
fact UnitLaw1 {
all a: Group.elements | Group.mult [a] [Group.unit] = a
}
fact UnitLaw2 {
all a: Group.elements |
Group.mult [Group.unit] [a] = a
}
fact AssociativeLaw {
all a: Group.elements | all b: Group.elements | all c:Group.elements |
Group.mult [Group.mult [a] [b]] [c] = Group.mult [a] [Group.mult [b] [c]]
}
fact InvLaw1{
all a: Group.elements | Group.mult [Group.inv[a]] [a] = Group.unit
}
assert InvLaw2 {
all a: Group.elements | Group.mult [a] [Group.inv[a]] = Group.unit
}
check InvLaw2
assert Commutativity {
all a: Group.elements | all b: Group.elements | Group.mult [a] [b] = Group.mult [b] [a]
}
check Commutativity for 6
pred subgroup (g: set Element, h: set Element) {
(all a: g | a in h) and
(Group.unit in g) and
(all a, b: g | Group.mult [a] [b] in g) and
(all a: g | Group.inv[a] in g)
}
pred regularSubgroup(n: set Element, g: set Element) {
subgroup [n, g] and
(all n0: n, g0: g | Group.mult [Group.mult [g0] [n0]] [Group.inv[g0]] in n)
}
pred main(n1: set Element, n2: set Element) {
let g = Group.elements |
regularSubgroup [n1, g] and
(some g0: g | (not g0 in n1)) and
regularSubgroup [n2, n1] and
(some n10: n1 | (not n10 in n2)) and
(not regularSubgroup [n2, g])
}
run main for 8
I think this should be reported as an issue on the https://github.com/alloytools/org.alloytools.alloy site? Preferably with a PR that fixes it.

Build json string from representative input

Can somebody direct me to a right approach ?
Do I need first to create a tree after parsing the input and then trasverse it ?
The input is given in the following form:
node11/node12/.../node1k
node21/node22/.../node2n
...
nodem1/nodem2/.../nodeml
Sample input:
a/b/c1
x/b
a/b/c/d
m
Output:
{
a: {
b: {
c: { d: "" },
c1: ""
}
},
x: { b: "" },
m: ""
}
Here is a JS solution that uses recursion to process each path.
function parse(paths) {
var resultObj = {};
paths.forEach(function(path) {
var nodes = path.split("/");
recurse(nodes, resultObj);
});
console.log(resultObj);
console.log(JSON.stringify(resultObj));
}
function recurse(path, obj) {
if (!path.length)
return obj;
var node = path.shift();
if (!obj.hasOwnProperty(node))
obj[node] = path.length ? {} : "";
return recurse(path, obj[node]);
}
var arr = ["a/b/c1", "x/b", "a/b/c/d", "m"];
parse(arr);
If you want to do this in python, you could do this:
output = {}
lines = ["a/b/c1", "x/b", "a/b/c/d", "m"]
for line in lines:
nodePath = line.split('/')
current = output
for node in nodePath[:-1]:
current[node] = {} if node not in current else current[node]
current = current[node]
current[nodePath[-1]] = ""
print output # gives us {'a': {'b': {'c1': '', 'c': {'d': ''}}}, 'x': {'b': ''}, 'm': ''}
Then turn output into json however you want.

Scala/Java reflective programming: invoke constructor by typecasted arguments

In the library json4s, I intend to write a weakly typed deserializer for some malformed data (mostly the result of XML -> JSON conversions)
I want the dynamic program to get the type information of a given constructor (easy, e.g. 'Int'), apply it on a parsed string (e.g. "12.51"), automatically convert string into the type (in this case 12.51 should be typecasted to 13), then call the constructor.
I come up with the following implementation:
import org.json4s.JsonAST.{JDecimal, JDouble, JInt, JString}
import org.json4s._
import scala.reflect.ClassTag
object WeakNumDeserializer extends Serializer[Any] {
def cast[T](cc: Class[T], v: Any): Option[T] = {
implicit val ctg: ClassTag[T] = ClassTag(cc)
try {
Some(v.asInstanceOf[T])
}
catch {
case e: Throwable =>
None
}
}
override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Any] = Function.unlift{
tuple: (TypeInfo, JValue) =>
tuple match {
case (TypeInfo(cc, _), JInt(v)) =>
cast(cc, v)
case (TypeInfo(cc, _), JDouble(v)) =>
cast(cc, v)
case (TypeInfo(cc, _), JDecimal(v)) =>
cast(cc, v)
case (TypeInfo(cc, _), JString(v)) =>
cast(cc, v.toDouble)
case _ =>
None
}
}
}
However executing the above code on a real Double => Int case always yield IllegalArgumentException. Debugging reveals that the line:
v.asInstanceOf[T]
does not convert Double type to Int in memory, it remains as a Double number after type erasure, and after it is used in reflection to call the constructor it triggers the error.
How do I bypass this and make the reflective function figuring this out?
Is there a way to tell the Java compiler to actually convert it into an Int type?
UPDATE: to help validating your answer I've posted my test cases:
case class StrStr(
a: String,
b: String
)
case class StrInt(
a: String,
b: Int
)
case class StrDbl(
a: String,
b: Double
)
case class StrIntArray(
a: String,
b: Array[Int]
)
case class StrIntSeq(
a: String,
b: Seq[Int]
)
case class StrIntSet(
a: String,
b: Set[Int]
)
class WeakSerializerSuite extends FunSuite with TestMixin{
implicit val formats = DefaultFormats ++ Seq(StringToNumberDeserializer, ElementToArrayDeserializer)
import org.json4s.Extraction._
test("int to String") {
val d1 = StrInt("a", 12)
val json = decompose(d1)
val d2 = extract[StrStr](json)
d2.toString.shouldBe("StrStr(a,12)")
}
test("string to int") {
val d1 = StrStr("a", "12")
val json = decompose(d1)
val d2 = extract[StrInt](json)
d2.toString.shouldBe("StrInt(a,12)")
}
test("double to int") {
val d1 = StrDbl("a", 12.51)
val json = decompose(d1)
val d2 = extract[StrInt](json)
d2.toString.shouldBe("StrInt(a,12)")
}
test("int to int array") {
val d1 = StrInt("a", 12)
val json = decompose(d1)
val d2 = extract[StrIntArray](json)
d2.copy(b = null).toString.shouldBe("StrIntArray(a,null)")
}
test("int to int seq") {
val d1 = StrInt("a", 12)
val json = decompose(d1)
val d2 = extract[StrIntSeq](json)
d2.toString.shouldBe("StrIntSeq(a,List(12))")
}
test("int to int set") {
val d1 = StrInt("a", 12)
val json = decompose(d1)
val d2 = extract[StrIntSet](json)
d2.toString.shouldBe("StrIntSet(a,Set(12))")
}
test("string to int array") {
val d1 = StrStr("a", "12")
val json = decompose(d1)
val d2 = extract[StrIntArray](json)
d2.copy(b = null).toString.shouldBe("StrIntArray(a,null)")
}
test("string to int seq") {
val d1 = StrStr("a", "12")
val json = decompose(d1)
val d2 = extract[StrIntSeq](json)
d2.toString.shouldBe("StrIntSeq(a,List(12))")
}
test("string to int set") {
val d1 = StrStr("a", "12")
val json = decompose(d1)
val d2 = extract[StrIntSet](json)
d2.toString.shouldBe("StrIntSet(a,Set(12))")
}
I've found the first solution, TL:DR: its totally absurd & illogical, and absolutely full of boilerplates for a established strongly typed language. Please post your answer deemed any better:
abstract class WeakDeserializer[T: Manifest] extends Serializer[T] {
// final val tpe = implicitly[Manifest[T]]
// final val clazz = tpe.runtimeClass
// cannot serialize
override def serialize(implicit format: Formats): PartialFunction[Any, JValue] = PartialFunction.empty
}
object StringToNumberDeserializer extends WeakDeserializer[Any] {
override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Any] = {
case (TypeInfo(cc, _), JString(v)) =>
cc match {
case java.lang.Byte.TYPE => v.toByte
case java.lang.Short.TYPE => v.toShort
case java.lang.Character.TYPE => v.toInt.toChar
case java.lang.Integer.TYPE => v.toInt
case java.lang.Long.TYPE => v.toLong
case java.lang.Float.TYPE => v.toFloat
case java.lang.Double.TYPE => v.toDouble
case java.lang.Boolean.TYPE => v.toBoolean
//TODO: add boxed type
}
}
}
object ElementToArrayDeserializer extends WeakDeserializer[Any] {
val listClass = classOf[List[_]]
val seqClass = classOf[Seq[_]]
val setClass = classOf[Set[_]]
val arrayListClass = classOf[java.util.ArrayList[_]]
override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Any] = {
case (ti# TypeInfo(this.listClass, _), jv) =>
List(extractInner(ti, jv, format))
case (ti# TypeInfo(this.seqClass, _), jv) =>
Seq(extractInner(ti, jv, format))
case (ti# TypeInfo(this.setClass, _), jv) =>
Set(extractInner(ti, jv, format))
case (ti# TypeInfo(this.arrayListClass, _), jv) =>
import scala.collection.JavaConverters._
new java.util.ArrayList[Any](List(extractInner(ti, jv, format)).asJava)
case (ti# TypeInfo(cc, _), jv) if cc.isArray =>
val a = Array(extractInner(ti, jv, format))
mkTypedArray(a, firstTypeArg(ti))
}
def mkTypedArray(a: Array[_], typeArg: ScalaType) = {
import java.lang.reflect.Array.{newInstance => newArray}
a.foldLeft((newArray(typeArg.erasure, a.length), 0)) { (tuple, e) => {
java.lang.reflect.Array.set(tuple._1, tuple._2, e)
(tuple._1, tuple._2 + 1)
}}._1
}
def extractInner(ti: TypeInfo, jv: JValue, format: Formats): Any = {
val result = extract(jv, firstTypeArg(ti))(format)
result
}
def firstTypeArg(ti: TypeInfo): ScalaType = {
val tpe = ScalaType.apply(ti)
val firstTypeArg = tpe.typeArgs.head
firstTypeArg
}
}

how to generate a java array from a scala case class

I'm writing a small data access library to help me use Cassandra prepared statements in a Scala program (its not open source but maybe one day). What I'd like to do is automatically generate a Java Array for the bind statement from the case class
com.datastax.driver.core
PreparedStatement...
public BoundStatement bind(Object... values);
So currently I have
case class Entity(foo:String, optionalBar:Option[String])
object Entity {
def toJArray(e:Entity) = { Array(e.foo, e.optionalBar.getOrElse(null)) }
}
val e1 = Entity("fred", Option("bill"))
val e2 = Entity("fred", None)
Entity.toJArray(e1)
res5: Array[String] = Array(fred, bill)
Entity.toJArray(e2)
res6: Array[String] = Array(fred, null)
The toJArray returns an Array I can use in the bind statement. The boiler plate code gets worse if there is a date or double or a java enum
new java.util.Date(createdOn)
scala.Double.box(price)
priceType.name
Is there a way of automatically generating the Array in Scala assuming the bind parameters have the same order as the case class fields?
EDIT Thanks to #srgfed01
Here's what I came up with (not complete) but allows me to do something like
val customer1 = Customer( "email", "name", None, Option(new Date), OrdStatus.New)
session.execute(populate(customer1, insert))
val customer2 = Customer( "email2", "name2", Option(22), Option(new Date), OrdStatus.Rejected)
session.execute(populate(customer2, insert))
using this function
def populate(state:Product, statement:PreparedStatement): BoundStatement = {
def set(bnd:BoundStatement, i:Int, aval:Any): Unit = {
aval match {
case v:Date => bnd.setDate(i, v)
case v:Int => bnd.setInt(i, v)
case v:Long => bnd.setLong(i, v)
case v:Double => bnd.setDouble(i, v)
case v:String => bnd.setString(i, v)
case null => bnd.setToNull(i)
case _ => bnd.setString(i, aval.toString)
}
}
val bnd = statement.bind
for(i <- 0 until state.productArity) {
state.productElement(i) match {
case op: Option[_] => set(bnd, i, op.getOrElse(null))
case v => set(bnd, i, v)
}
}
bnd
}
You can use productIterator call for your case class object:
case class Entity(foo: String, optionalBar: Option[String])
val e1 = Entity("fred", Option("bill"))
val e2 = Entity("fred", None)
def run(e: Entity): Array[Any] = e.productIterator
.map {
case op: Option[_] => op.getOrElse(null)
case v => v
}
.toArray
println(run(e1).mkString(" ")) // fred bill
println(run(e2).mkString(" ")) // fred null

Categories