i am trying to set final properties in Groovy source (used in a Grails project) and following some examples but somehow i does not seem to work and i cannot find out why..
class Foo {
final x
Foo(Map m=[:]) {
m.each { key, value -> this.#"$key" = value }
}
}
def foo = new Foo(x:1)
I am getting the error:
Cannot set the property 'x' because the backing field is final.
According to some posts found on the internet this should work.
Why does fail how can is set the properties via a map when using a final field?
You can achieve the result you seek by using the #Immutable annotation
#Immutable
class Foo {
def x
}
Then this can be called as
def foo = new Foo([:])
or
def foo = new Foo(x:42)
and then later
foo.x = 43
causes
ERROR groovy.lang.ReadOnlyPropertyException:
Cannot set readonly property: y for class: Foo
I don't know why your constructor with a Map argument doesn't work, but this constructor does:
class Foo {
final x
Foo(x) {
this.x = x
}
}
def foo = new Foo(1)
I think, You should use #MapConstructor annotation
#ToString(includePackage = false, includeNames = true)
#MapConstructor
class A {
#Final
String x
int y
}
def a = new A(x: 'david', y: 12)
println "a = $a"
Related
This one has been bothering me for a while.
It seems like it's impossible to use the with-method in a trait.
Example:
class P {
int prop
}
trait T {
P pogo = new P().with {
prop = 42 // MissingPropertyException: No such property: prop for class: C
return it
}
}
class C implements T {
}
def pogo = new C().pogo
assert pogo.prop == 42
Can anyone explain why that is?
The code is borrowed from this old thing.
(Comment, but need answer formatting.)
It needs to be it.prop = 42, although I don't recall why.
Maybe because C hasn't been fully constructed yet? It's been awhile.
trait T {
P pogo = new P().with {
it.prop = 42
return it
}
}
def pogo = new C().pogo
println(pogo.prop)
assert pogo.prop == 42
def c = new C()
c.pogo.prop = 12
assert c.pogo.prop == 12
I'm trying to access a type defined in the upper-level module:
module MainModule
type Data = { stuff }
module XmlDeserialization =
type Data() =
[<XmlAttribute("stuff")>]
member val stuff ...
member x.ToDomainType() =
{
stuff = x.stuff
} : MainModule.Data
The problem is, the last line doesn't compile because "the type 'MainModule' isn't defined."
I'm able to achieve what I want using namespaces instead, but is it possible to do this using modules?
You cannot reference MainModule within the body of MainModule itself, because at that point, the module is technically not defined yet. This can be reproduced with a smaller program:
module M =
type T = T
let x: T = T // OK
let y: M.T = T // Error: module M is not defined yet
The simplest solution for you would be to finish defining MainModule before you start defining XmlDeserialization:
module MainModule =
type Data = { stuff }
module XmlDeserialization =
type Data() =
[<XmlAttribute("stuff")>]
member val stuff ...
member x.ToDomainType() =
{
stuff = x.stuff
} : MainModule.Data // Works now
But if you insist that XmlDeserialization be nested under MainModule, and you insist that the types must have the same name, then you can work around the type shadowing by creating an alias of the original type before defining the overshadowing one:
module XmlDeserialization =
// Alias the original type
type MainModule_Data = Data
type Data() =
[<XmlAttribute("stuff")>]
member val stuff ...
member x.ToDomainType() =
{
stuff = x.stuff
} : MainModule_Data // Refer by alias: works now
In this specific case, it should just work if you remove the type annotation. The compiler will infer the record type from the fields of the record Data.
In general, you can declare a function to enforce a given record type, for example:
let private mainModuleData (instance : Data) = instance
If this function is defined before Data gets shadowed, even if the record fields are ambiguous, you can use the function to enforce the correct type:
member x.ToDomainType() =
mainModuleData
{ stuff = x.stuff }
I am aware that Lua classes can be created using the OO system that Luabind exposes to Lua:
http://www.rasterbar.com/products/luabind/docs.html#defining-classes-in-lua
class 'lua_testclass'
function lua_testclass:__init(name)
self.name = name
end
function lua_testclass:print()
print(self.name)
end
a = lua_testclass('example')
a:print()
However I am unable to figure out how to scope the class within another namespace so I can do the following:
a = MyScope.lua_testclass('example')
a:print()
Anyone has a idea. I do not want my classes to pollute the global namespace in Lua.
Luabind's class function will always pollute the global table. However, you can clean up after it:
function newclass(name)
oldglobal = _G[name]
class(name)
cls = _G[name]
_G[name] = oldglobal
return cls
end
Then you would use it like this:
MyScope.lua_testclass = newclass 'lua_testclass'
Analogous to local mod = require 'mod' you have to spell the name of the class twice, but you could easily build another function on top of this that could be used like setclass(MyScope, 'lua_testclass'), automatically putting the class into MyScope:
function setclass(scope, name) scope[name] = newclass(name) end
Disclaimer: All this code is entirely untested.
I did mine a little differently, but it's generally the same concept. Mine doesn't create the class, but rather just moves it. I also implemented it on the C++ side.
To implement what I did in Lua, you would write:
function moveClass(name)
oldGlobal = _G[name]
_G[name] = nil
return oldGlobal
end
To implement it in C++, you would write:
luabind::module(lua) [
luabind::def("moveClass", +[](lua_State * lua, std::string name) {
// In the case the class does not exist, this will just
// remove nil and return nil. That essentially does nothing.
luabind::object oldGlobal = luabind::globals(lua)[name];
luabind::globals(lua)[name] = luabind::nil;
return oldGlobal;
})
];
So now if you were to use that to move a class you created, you would do this:
class 'MyClass'
myTable = {}
myTable.MyClass = moveClass 'MyClass'
As an extra note, if you want the moveClass function to give an error in the case that the class you are trying to move does not exist, use luabind::type(oldGlobal) == LUA_TNIL to determine if the class existed or not.
Example:
luabind::module(lua) [
luabind::def("moveClass", +[](lua_State * lua, std::string name) {
luabind::object oldGlobal = luabind::globals(lua)[name];
if (luabind::type(oldGlobal) == LUA_TNIL) {
throw std::runtime_error("Class does not exist.");
}
luabind::globals(lua)[name] = luabind::nil;
return oldGlobal;
})
];
I'm not sure where i'm going wrong, but it seems that I'm not able to copy properties from an object instance and assign them to a map without the values being changed after saving the instance.
This is a sample class:
class Product {
String productName
String proudctDescription
int quantityOnHand
}
Once the form is submitted and it's sent to my controller, I can access the values and manipulate them from the productInstance.properties map that is available from the instance. I want to copy the properties to another map to preserve the values before committing them during an edit. So let's say we are editing a record and these are the values stored in the db: productName = "My Product", productDescription = "My Product Description" and quantityOnHand = 100.
I want to copy them to:
def propertiesBefore = productInstance.properties
This did not work, because when I save the productInstance, the values in propertiesBefore change to whatever the instance had.
So I tried this:
productInstance.properties.each { k,v -> propertiesBefore[k] = v }
Same thing happened again. I am not sure how to copy by value, it seems no matter what I try it copies by reference instead.
EDIT
As per the request of Pawel P., this is the code that I tested:
class Product {
String productName
String productDescription
int quantityOnHand
}
def productInstance = new Product(productName: "Some name", productDescription: "Desciption", quantityOnHand: 10)
def propertiesBefore = [:]
productInstance.properties.each { k,v -> propertiesBefore[k] = (v instanceof Cloneable) ? v.clone() : v }
productInstance.productName = "x"
productInstance.productDescription = "y"
productInstance.quantityOnHand = 9
println propertiesBefore.quantityOnHand // this will print the same as the one after the save()
productInstance.save(flush:true)
println propertiesBefore.quantityOnHand // this will print the same as the one above the save()
Without cloning, copying hash-map [:]'s values to a new hash-map [:]'s space can also be done by "pushing" the first one over, which would achieve the same result that you desired (copy by value)!
def APE = [:]
APE= [tail: 1, body: "hairy", hungry: "VERY!!!"]
def CAVEMAN = [:]
CAVEMAN << APE //push APE to CAVEMAN's space
//modify APE's values for CAVEMAN
CAVEMAN.tail = 0
CAVEMAN.body = "need clothes"
println "'APE': ${APE}"
println "'CAVEMAN': ${CAVEMAN}"
Output ==>
'APE': [tail:1, body:hairy, hungry:VERY!!!]
'CAVEMAN': [tail:0, body:need clothes, hungry:VERY!!!]
The problem is that you actually copy references to variables. To obtain copy of variable you should use clone(). Take a look:
class Product {
String productName
String productDescription
int quantityOnHand
}
def productInstance = new Product(productName: "Some name", productDescription: "Desciption", quantityOnHand: 10)
def propertiesBefore = [:]
productInstance.properties.each { k,v -> propertiesBefore[k] = (v instanceof Cloneable) ? v.clone() : v }
productInstance.productName = "x"
productInstance.productDescription = "y"
productInstance.quantityOnHand = 9
println productInstance.properties
println propertiesBefore
It prints:
[quantityOnHand:9, class:class Product, productName:x, productDescription:y]
[quantityOnHand:10, class:class Product, productName:Some name, productDescription:Desciption]
A simpler example for groovy using Hash-Map [:] can be like this:
def APE = [:]
APE= [tail: 1, body: "hairy", hungry: "VERY!!!"]
def CloneMe = APE //*APE as clone*
def CAVEMAN = [:] //*copy APE's values over thru mapping the clone*
CloneMe.each { key,value -> CAVEMAN[key] = (value instanceof Cloneable) ? value.clone() : value }
println "'CloneMe': ${CloneMe}"
//change some of the clone's values for CAVEMAN
CAVEMAN.tail = 0
CAVEMAN.body = "need clothes"
println "'APE': ${APE}"
println "'CAVEMAN': ${CAVEMAN}"
Output ==>
'CloneMe': [tail:1, body:hairy, hungry:VERY!!!]
'APE': [tail:1, body:hairy, hungry:VERY!!!]
'CAVEMAN': [tail:0, body:need clothes, hungry:VERY!!!]
Let's say i have code like this :
class A{ foo() => "A";}
class B{ foo() => "B";}
class C{ foo() => "C";}
class Mix extends A with B,C {
foo() => "MIX";
bar() => super.foo();
}
class MessABC = Object with A,B,C;
class MessBCA = Object with B,C,A;
class MessCAB = Object with C,A,B;
void main() {
Mix mix = new Mix();
MessABC mABC = new MessABC();
MessBCA mBCA = new MessBCA();
MessCAB mCAB = new MessCAB();
print("Mix.foo = ${mix.foo()} Mix.bar = ${mix.bar()} \n"
"mABC.foo = ${mABC.foo()} \n"
"mBCA.foo = ${mBCA.foo()} \n"
"mCAB.foo = ${mCAB.foo()} \n");
}
The output
Mix.foo = MIX Mix.bar = C
mABC.foo = C
mBCA.foo = A
mCAB.foo = B
On the mix object I can call both Mix.foo and C.foo with the super (actually i expected A.foo)
But can i somehow call A.foo and B.foo ?
Also i am a bit confused by the with semantics. A,B,C Looks like "one rank enumeration" but the order is important. And "Dart Editor" doesn't warn me about the name collision. Perhaps i can enable this warning?
To me it feels like something that makes you confused and error-prone.
Mixin application is processed from left to right.
The superclass of Object with A,B,C is Object with A,B, which again has the superclasses Object with A and then Object.
The overriding rules for mixins are the same as for non-mixin superclasses. Your C.foo in Mix overrides the ones inherited from A and B, so Mix.bar's super.foo() only reaches the C.foo, and there is no way to access A.foo or B.foo.
Overriding is perfectly ok, and doesn't cause any warnings, as long as the methods have compatible signatures.
The most thorough description of mixins is still https://www.dartlang.org/articles/mixins/