I have:
class XCClass
{
#native protected def createWin(displayPtr: Long, width: Int, height: Int, backGroundColour: Int = white.value,
borderColour: Int = darkblue.value, borderWidth: Int = 0, xPosn: Int = 0, yPosn: Int = 0): Long
#native protected def xOpen(): Long
System.load("/sdat/projects/prXCpp/Release/libprXCpp.so")
//Code edited out
class Window(width: Int, height: Int, backGroundColour: ColourInt = white, borderColour: ColourInt = darkblue,
borderWidth: Int = 0, xPosn: Int = 0, yPosn: Int = 0)
{
val xWinPtr = createWin(xServPtr, width, height, backGroundColour.value, borderColour.value, borderWidth, xPosn, yPosn)
#native def drawLine(x1: Int, y1: Int, x2: Int, y2: Int): Unit
}
}
The first two methods work fine, but the native method on the inner class gives
object XApp extends App
{
val xc:XCClass = XCClass()
val win: xc.Window = xc.Window(800, 600)
win.drawLine(20, 20, 40, 40)
readLine()
}
Exception in thread "main" java.lang.UnsatisfiedLinkError: pXClient.XCClass$Window.drawLine(IIII)V
Here's the C++ signature
extern "C" JNIEXPORT void JNICALL Java_pXClient_XCClass$Window_drawLine(JNIEnv * env, jobject c1, Display *dpy,
Window win, jint x1, jint y1, jint x2, jint y2)
I tried using an underscore instead of the $ sign, and having no inner name at all but that failed as well.
Edit2: I managed to get javah to work just before seeing Robin's answer and it gave
JNIEXPORT void JNICALL Java_pXClient_XCClass_00024Window_drawLine
(JNIEnv *, jobject, jint, jint, jint, jint);
Edit4: It worked fine once I'd corrected errors in my code. It seems that the JVM will import a native function with the wrong parameter signature as long as the name is correct.
I just did a quick test with a .java file and javah, and a $ is represented as _00024.
Related
I am reading Programming in Scala, Third Edition (Also present in Fourth Edition), by Lex Spoon; Bill Venners; Martin Odersky, and trying out examples along the way.
Following example form the book | Run in ScalaFiddle
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class UniformElement(
ch: Char,
override val width: Int,
override val height: Int
) extends Element {
private val line = ch.toString * width
def contents = Array.fill(height)(line)
}
val e: Element = new UniformElement('x', 2, 3)
gives java.lang.NullPointerException, when tried in REPL, or in Eclipse worksheet.
If I change
private val line = ch.toString * width
to
private def line = ch.toString * width
no error occurs.
Can someone explain, please?
I am using scala 2.11.8
The problem here is that contents is still not defined in the constructor, when you define line. If line is a val, it does not pick the overridden width, instead it uses the abstract one which in turn uses contents, which is still undefined and you get the NPE. You can see this by looking at the stacktrace and noting that the NPE is thrown by the definition of width in the abstract class.
When line is defined as a method, it does not execute until you call it and by that time contents will be fully defined, because it can call line (another method) which will be fully defined.
Run on ScalaFiddle
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class UniformElement(
ch: Char,
override val width: Int,
override val height: Int
) extends Element {
private def line: String = ch.toString * width
def contents = Array.fill(height)(line)
}
val e3: Element = new UniformElement('x', 2, 3)
Bottom line: you have a kind of "circular dependency" between line and contents.
It sounds really stupid, but i couldn't find the answer neither on StackOverflow or in Google as well. I need to make really simple and easy thing - pass to my TestNG test a Dataprovider that contains two numbers in each set, but i didn't manage to succeed with it . Here's my code:
#DataProvider(name = "numbersRandomRange")
def numbersRandomRange() = {
Array(Array(100, 150),
Array(100.10, 200.01),
Array(100.10f, 250.10f)
)
}
My test looks like this :
`
#Test(dataProvider = "numbersRandomRange")
def testNumbersRandomRange(min: Any, max: Any) {
def calculate(minValue: Any, maxValue: Any): Any = (minValue, maxValue) match {
case (min: Int, max: Int) => alpha.number(min, max)
case (min: Double, max: Double) => alpha.double(min, max)
case (min: Float, max: Float) => alpha.float(min, max)
}
val actualNumber = calculate(min, max)
logger.info("Checking custom number with type function. Should return with specific type and below specified value : ")
expectResult(actualNumber.getClass)(min.getClass)
assert(util.less(actualNumber, max))
assert(util.less(min, actualNumber))
}
`
When i try to run it, i get next Error Message :
Data Provider public java.lang.Object[] must return either Object[][] or Iterator [], not class [Ljava.lang.Object;
If you annotate the type then it works:
#DataProvider(name = "numbersRandomRange")
def numbersRandomRange():Array[Array[Any]] = { //Notice that the return type is set
Array(Array(100, 150),
Array(100.10, 200.01),
Array(100.10f, 250.10f)
)
}
The scala compiler is inferring the return type of numbersRandomRange to be Array[Array[_ >: Float with Double with Int <: AnyVal]] which is then probably interpreted by java to just be Object. By giving the compiler a hint, it makes this work.
So if I have the following object:
case class Purple(x: Int, y: Int, z: Int)
and I want to make a method that adds 25 to only one of the members.
I would imagine the following (if I want to add it to x):
def add25ToX(purple: Purple) : Purple = {
this.x + 25 }
But I can't because it wants Purple back and not an Int. How do I get around this issue?
This is the basic principle of immutable structures: you don't modify the existing data. Instead, you return a new Purple with a modified value. You can use the copy constructor for conciseness:
def add25ToX(purple: Purple): Purple = purple.copy(x = purple.x + 25)
Alternatively you can define it inside the class
case class Purple(x: Int, y: Int, z: Int) {
def add25ToX: Purple = this.copy(x = x + 25)
}
I'd like a container class that I can extend with some number of traits to contain groups of default vals that can later be changed in an immutable way. The traits will hold certain simple pieces of data that go together so that creating the class with a couple of traits will create an object with several collections of default values.
Then I'd like to be able to modify any of the vals immutably by copying the object while changing one new value at a time.
The class might have something like the following:
class Defaults(val string: String = "string", val int: Int = "int")
Then other traits like this
trait MoreDefaults{
val long: Long = 1l
}
Then I'd like to mix them when instantiated to build my the particular needed set of defaults
var d = new Defaults with MoreDefaults
and later to something like:
if (someFlag) d = d.copy( long = 1412341234l )
You can do something like this with a single case class but I run out of params at 22. But I'll have a bunch of groupings of defaults I'd like to mixin depending on the need, then allow changes to any of them (class defined or trait defined) in an immutable way.
I can stick a copy method in the Defaults class like this:
def copy(
string: String = string,
int: Int = int): Defaults = {
new Defaults(string, int)
}
then do something like
var d = new Defaults
if (someFlag) d = d.copy(int = 234234)
Question ====> This works for values in the base class but I can't figure how to extend this to the mixin traits. Ideally the d.copy would work on all vals defined by all of the class + traits. Overloading is trouble too since the vals are mainly Strings but all of the val names will be unique in any mix of class and traits or it is an error.
Using only classes I can get some of this functionality by having a base Defaults class then extending it with another class that has it's own non-overloaded copyMoreDefault function. This is really ugly and I hope a Scala expert will see it and have a good laugh before setting me straight--it does work though.
class Defaults(
val string: String = "one",
val boolean: Boolean = true,
val int: Int = 1,
val double: Double = 1.0d,
val long: Long = 1l) {
def copy(
string: String = string,
boolean: Boolean = boolean,
int: Int = int,
double: Double = double,
long: Long = long): Defaults = {
new Defaults(string, boolean, int, double, long)
}
}
class MoreDefaults(
string: String = "one",
boolean: Boolean = true,
int: Int = 1,
double: Double = 1.0d,
long: Long = 1l,
val string2: String = "string2") extends Defaults (
string,
boolean,
int,
double,
long) {
def copyMoreDefaults(
string: String = string,
boolean: Boolean = boolean,
int: Int = int,
double: Double = double,
long: Long = long,
string2: String = string2): MoreDefaults = {
new MoreDefaults(string, boolean, int, double, long, string2)
}
}
Then the following works:
var d = new MoreDefualts
if (someFlag) d = d.copyMoreDefaults(string2 = "new string2")
This method will be a mess if Defaults get's changed parameters! All the derived classes will have to be updated--ugh. There must be a better way.
I don't think I'm strictly speaking answering your question, rather suggesting an alternative solution. So your having problems with large case classes, e.g.
case class Fred(a: Int = 1, b: Int = 2, ... too many params ... )
What I would do is organize the params into more case classes:
case class Bar(a: Int = 1, b: Int = 2)
case class Foo(c: Int = 99, d: Int = 200)
// etc
case class Fred(bar: Bar = Bar(), foo: Foo = Foo(), ... etc)
Then when you want to do a copy and change, say one of the values of Foo you do:
val myFred: Fred = Fred()
val fredCopy: Fred = myFred.copy(foo = myFred.foo.copy(d = 300))
and you need not even define the copy functions, you get them for free.
I am having some serious troubles implementing a draw in the scala language. my current code looks like:
package edu.luc.cs.laufer.cs473.shapealgebra
import java.awt.Graphics2D
class Draw {
def draw(g: Graphics2D)(s: Shape): Unit = s match {
case Ellipse(hw, hh) => g.drawArc(-hw, -hh, 2 * hw, 2 * hh, 0, 360)
case Rectangle(w, h) => g.drawRect(0, 0, w, h)
case Location(x: Int, y: Int, shape: Shape) => {
g.translate(x, y)
draw(g)(shape)
g.translate(0,0)
}
case Group(shapes # _*) => {
shapes foreach(draw(g)(_))
}
}
}
object Draw extends Draw {
def apply(g: Graphics2D) = draw(g)(_)
}
The problem here is with my group case. It does not draw a group of shapes properly. The two test cases uses the following shapes:
val simpleLocation = Location(70, 30, Rectangle(80, 120))
val complexGroup = Location(50, 100,
Group(
Ellipse(20, 20),
Location(150, 50,
Group(
Rectangle(50, 30),
Rectangle(300, 60),
Location(100, 200,
Ellipse(50, 50)
)
)
),
Rectangle(100, 200)
)
)
The complex continues to fail and I can't figure out why.
package edu.luc.cs.laufer.cs473.shapealgebra
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.FunSuite
import java.awt.image.BufferedImage
import TestFixtures._
#RunWith(classOf[JUnitRunner])
class TestDraw extends FunSuite with BufferedImageEquality {
test("simple") {
val s = simpleLocation
val i = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
Draw(i.createGraphics())(s)
val j = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
val g = j.createGraphics()
g.translate(70, 30)
g.drawRect(0, 0, 80, 120)
assertEquals(i, j)
}
test("complex") {
val s = complexGroup
val i = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
Draw(i.createGraphics())(s)
val j = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
val g = j.createGraphics()
paintComplexGroup(g)
assertEquals(i, j)
}
}
The test case is shown above. I get a "0 did not equal 255" from the result of the unit test.
If you look at what translate does, the Javadoc says
"Translates the origin of the Graphics2D context to the point (x, y)
in the current coordinate system."
So
g.translate(0,0)
does nothing. Try
g.translate(-x, -y)
Although, if it were me, I wouldn't mess with the Graphics object's origin. I'd modify the drawRect and drawArc statements to take a location, and pass the location co-ordiates as an argument to the method.
I see you are calling translate on g: Graphics2D, which mutates that object. However, you are not undoing that mutation once you finish drawing the translated objects. Furthermore, there's also the question of whether you expect the translation to be cumulative (for example, the second translation be absolute 200, 150, instead of absolute 150, 50).
Might this the problem you see?