How to add nested message into already created message ? (in Scala) - scala

After adding nested message i recieve nested messages from main message and got nothing.
You can see it in logs: 1 and 2. Size of List 0 !
Any ideas?
message PacketPlayers
{
repeated PacketPlayer players = 1;
}

ScalaPB case classes are immutable. In your example, addPlayers would not modify the instance it's called on, but return a new instance of PacketPlayer that has the additional players.
It is possible to avoid mutable arrays and vars in constructing the new object. For example:
val players = onlinePlayers.keySet.map(makePacketPlayer)
val packetPlayers = PacketPlayers().withPlayers(players)

Related

Use any previous message in a new message

I have a protobuf file in which I define multiple messages which all inherit the same trait (using option (scalapb.message).extends = "Event"; inside of message definition).
I would like to create a new message called MultiEvent which may contain sequence of any of the messages inherited from Event.
Event is defined as simple trait Event in scala code.
The idea is to be able to send special message which contains multiple of messages at once.
syntax = "proto3";
import "scalapb/scalapb.proto";
package com.some.package;
message A {
option (scalapb.message).extends = "Event";
string name = 1;
}
message B {
option (scalapb.message).extends = "Event";
string field = 1;
}
message C {
option (scalapb.message).extends = "Event";
string otherField = 1;
}
message MultiEvent {
option (scalapb.message).extends = "Event";
repeated Event seq = 1; // this line is problematic
}
I got the error: "Event" is not defined..
Ideally from the code the field would be a simple Seq, which repeated provides, but it works only with scalar types.
I have found on internet that Any may be able to accomplish what I want, but I get errors when try to use it.
What is the usual way of solving problems like this? Enum? Conversion?
Thanks.
The usual way is oneof (in Protocol Buffers 3). repeated oneof is illegal:
Repeated oneof was in the initial proposal but as we later found out, there were lots many complicated corner cases in wire and API. We decided not to add repeated for oneof.
You can always define a message which wraps a oneof and have a repeated field of that message instead.
so
message Event {
oneof sealed_value {
A a = 1;
B b = 2;
C c = 3;
...
}
}
and then repeated Event as you currently have.
Using sealed_value as the name enables ScalaPB's sealed oneof support.

Accessing Constants which rely on a list buffer to be populated Scala

Encountering a problem whereby I am specifying Private Constants at the start of a scala step definiton file which relies on a List Buffer element to be populated, however when compiling I get a 'IndexOutOfBoundsException' because the list is empty initially and only gets populated later in a for loop.
For Example I have the following 2 constants:
private val ConstantVal1= globalExampleList(2)
private val ConstantVal2= globalExampleList(3)
globalExampleList is populated further down in the file using a for loop:
for (i <- 1 to numberOfW) {
globalExampleList += x.xy }
This List Buffer adds as many values as required to a global mutable ListBuffer.
Is there a better way to declare these constants? I've tried to declare them after the for loop but then other methods are not able to access these. I have around 4 different methods within the same file which use these values and instead of accessing it via index each time i thought it would be better to declare them as a constant to keep it neat and efficient for whenever they require changing.
Thanks
You can create list buffer of necessary size with default value and populate it later:
val globalExampleList: ListBuffer[Int] = ListBuffer.fill(numberOfW)(0)
for (i <- 0 until numberOfW) {
globalExampleList(i) = x.xy
}
But ConstantVal1, ConstantVal2 will still have original default value. So you can make them vars and re-assign them after you populate the buffer.
Your code seems to have a lot of mutations and side effects.
You have 2 ways to go.
First you can use lazy modifier
private lazy val ConstantVal1= globalExampleList(2)
private lazy val ConstantVal2= globalExampleList(3)
Or you can write the two lines after the for loop.
val globalExampleList = XXXX
for (i <- 1 to numberOfW) { globalExampleList += x.xy }
private val ConstantVal1= globalExampleList(2)
private val ConstantVal2= globalExampleList(3)

ScalaFX How do I create a method to react to changes in a var (ObjectProperty)?

I am making a multiplayer game client with ScalaFX GUI and Akka remoting for networking. When my client receives game data it stores it inside Model.gameData. I need my GUI to respond to this variable change.
I used gameData to create data:ObjectProperty in my Model object:
object Model {
var gameData:Option[GameData] = None
val data = new ObjectProperty(this,"data",Model.gameData)
...
}
drawGrid and drawPlayer are methods I use to update the GUI, located in CleintGUI object. I tired using addListener and onChange, they compile but the methods I placed inside of them are never invoked.
object ClientGUI extends JFXApp{
...
Model.data.addListener{ (o: javafx.beans.value.ObservableValue[_ <:Option[GameData]], oldVal: Option[GameData], newVal: Option[GameData]) =>
drawGrid
drawPlayer
}
Model.data onChange {
drawGrid
drawPlayer
}
}
What am I missing? Am I declaring data:ObectProperty or methods inside my ClientGUI incorrectly?
drawGrid and drawPlayer both work when I call them manually by creating an event through submitting a string in a TextField. When I receive GameData I also tried to directly call drawGrid and drawPlayer form inside of my actor class, but I got an error "Not an FX thread".
Edit: I got the GUI to update by mutating control attributes. However, ideally I would want to define the control attributes by using conditional expressions:
val data = new BooleanProperty(this,"data",Model.gameData.isDefined)
val msgLabel = new Label{
text <== when(data) choose " " otherwise "No GameData"
}
But this doesn't work as I can't figure out a way to define BooleanProperty such that when(data) changes value depending on boolean Model.gameData.isDefined
I was adding new elements to the GUI when I received gameData, by using GridPane.add method.
Instead of doing that I added all the controls(gui nodes/elements) during object creation and then changed their relevant attributes when I receive gameData.
e.g. I set Label.text from "No Game Data" to an empty string when I receive gameData:
def update {
ClientGUI.msgLabel = " "
}
I don't think this is the best approach as now I have publicly available vars in a multi threaded application, but since I only change them from one place when I receive new data it should be fine.
Ideally I would want to define the control attributes by using conditional expressions:
val data = new BooleanProperty(this,"data",Model.gameData.isDefined)
val msgLabel = new Label{
text <== when(data) choose " " otherwise "No GameData"
}
But this doesn't work as I can't figure out a way to define BooleanProperty such that when(data) changes value depending on boolean Model.gameData.isDefined

LinkedHashMap variable is not accessable out side the foreach loop

Here is my code.
var link = scala.collection.mutable.LinkedHashMap[String, String]()
var fieldTypeMapRDD = fixedRDD.mapPartitionsWithIndex((idx, itr) => itr.map(s => (s(8), s(9))))
fieldTypeMapRDD.foreach { i =>
println(i)
link.put(i._1, i._2)
}
println(link.size)// here size is zero
I want to access link out side loop .Please help.
Why your code is not supposed to work:
Before your foreach task is started, whole your function's closure inside foreach block is serialized and sent first to master, then to each of workers. This means each of them will have its own instance of mutable.LinkedHashMap as copy of link.
During foreach block each worker will put each of its items inside its own link copy
After your task is done you have still empty local link and several non-empty former copies on each of worker nodes.
Moral is clear: don't use local mutable collections with RDD. It's just not going to work.
One way to get whole collection to local machine is collect method.
You can use it as:
val link = fieldTypeMapRDD.collect.toMap
or in case of need to preserve the order:
import scala.collection.immutable.ListMap
val link = ListMap(fieldTypeMapRDD.collect:_*)
But if you are really into mutable collections, you can modify your code a bit. Just change
fieldTypeMapRDD.foreach {
to
fieldTypeMapRDD.toLocalIterator.foreach {
See also this question.

Two dimensional arrays of type actors

I am new to scala and I am trying to implement a system of multiple actors of same type. I am using Akka Actors for the same. I want to keep these actors in a two dimensional array but i am not able to initialize the 2d array. Below is the actor initialization.
var fighter1 : ActorRef = system.actorOf(Props[Fighter],name = "fighter1")
//2d array of type Actor(Fighter)
var LocationMatrix= Array.ofDim[Fighter](3,3)
//initialization
LocationMatrix(0)(1)=fighter1 //this throws error
fighter1 is of type ActorRef and LocationMatrix holds Fighter objects therefore you cannot put fighter1 inside it.
Try with this:
var locationMatrix = Array.ofDim[ActorRef](3,3)