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/
Related
This isn't a question, but rather a cautionary tale:
I tried to save some space and declared my variables in Jenkins Declarative pipeline like so:
int a, b, c
Then, I initialized them as:
a = b = c = 0
In my code, I use these integers as counters in a for-loop. My script kept failing over and over, some of the exceptions thrown:
java.lang.NullPointerException: Cannot invoke method next() on null object
and I knew for sure that my list is valid since it was hard-coded.
So, I started wondering what's going on with these counters and when I called getClass() on them, Jenkins happily told me that they weren't integers, but rather
org.codehaus.groovy.runtime.NullObject
After changing code to
int a = 0
int b = 0
int c = 0
everything worked like a charm.
Just wanted to share this. Maybe it'll help someone to save some frustration.
Jenkins pipelines execute Groovy code in the continuation-passing style using groovy-cps interpreter. This is not vanilla Groovy you can execute directly in the IDE or in Groovy Shell.
Groovy CPS transforms your code to support the continuation-passing style and the correct Groovy expression like:
a = b = c = 0
gets transformed to something that looks more like:
eval(
var("a"),
assign(
eval(
var("b"),
assign(
eval(
var("c"),
assign(0)
)
)
)
)
)
The problem with this expression in the CPS interpreter is that the assignment does not return any value, and thus the null value gets assigned to the variable b, and the same thing happens to the variable a.
If you want to dig deeper in the CPS invocations block, you can clone groovy-cps project and write a simple test case in the com.cloudbees.groovy.cps.CpsTransformerTest class.
#Test
void testMultiVariablesInlineCPS() {
def cps = parseCps('''
int a, b, c
a = b = c = 0
''')
println cps
}
Then you can put a breakpoint at the println cps and run the debugger. When you open the inspection window, you will see the picture similar to this one:
As a side note, keep in mind that the Groovy compiler also transforms your single line assignments when compiled the code to the bytecode. If you compile a simple Groovy script like:
int a, b, c
a = b = c = 0
println "$a $b $c"
and then you open its class file in the IDE to decompile the bytecode to the Java equivalent, you will see something like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.GStringImpl;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class test extends Script {
public test() {
CallSite[] var1 = $getCallSiteArray();
}
public test(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, test.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
int a = 0;
int b = 0;
int c = 0;
byte var5 = 0;
return var1[1].callCurrent(this, new GStringImpl(new Object[]{Integer.valueOf(var5), Integer.valueOf(var5), Integer.valueOf(var5)}, new String[]{"", " ", " ", ""}));
}
}
No matter how I approach Lua, I run into this error all the time, so I must not understand something inherit to the language:
attempt to call method 'func' (a nil value)
I've seen the error here a few times as well but the problem doesn't seem clear to me.
Here's my module:
actor.lua
Actor = {
x = 0,
mt = {},
new = function()
local new_actor = {}
new_actor.x = Actor.x
new_actor.mt = Actor.mt
return new_actor
end,
test = function(self, a, b)
print(a, b)
end
}
I'm using Löve.
main.lua
require "game/actor"
local a = Actor:new() --works fine
function love.load()
a.x = 10
print(a.x) --output: 10
a:test(11, 12) --error: attempt to call method 'test' (a nil value)
end
I'm also not sure when it's appropriate to use the previous styling over this in a module.
Actor = {
x = 0
}
Actor.mt = {}
function Actor.new()
print(42)
end
I'm honestly not sure what is more correct than the other but considering I run into a simple error either way, there's probably something I'm missing entirely?
It looks like you're trying to instance a kind of class made of metatables. You basically need to assign new_actor's metatable with Actor.mt. (Resuming the problem: when you're indexing new_actor you're not indexing Actor in this case)
setmetatable(new_actor, Actor.mt);
Even if the metatable is being added, it won't work until you put the meta "__index" event to index a table containing your class methods/values, in this case:
Actor.mt = {
__index = Actor
};
I'd suggest moving your class methods/values into a new table, like Actor.prototype, Actor.fn, etc... avoiding conflicts:
Actor.fn = {
test = function(self, a, b)
print(a, b)
end
};
Actor.mt = {
__index = Actor.fn
};
More about metatables in Lua 5.3 manual.
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 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"