Testing for identical objects in Dart - dart

According to the documentation, the function identical checks whether two references are to the same object.
With that in mind, I don't understand why the following is the case:
int a = 1;
int b = 1;
print(identical(a, b)); // prints 'true'
Map c = { 1: 'y' };
Map d = { 1: 'y' };
print(identical(c, d)); // prints 'false'
I'd expect both calls to return 'false'.

identical compares references. a and b are references to a compile time literal 1. Thus they are identical.

Related

Optional positional parameter in Dart

I'm studying recursion and I wrote this method to calculate the N° number of the Fibonacci series:
fibonacci(int n, Map memo) {
if (memo.containsKey(n)) return memo[n]; // Memo check
if (n <= 2) return 1; // base case
// calculation
memo[n] = fibonacci(n - 1, memo) + fibonacci((n - 2), memo);
return memo[n];
}
I think it doesn't need to be explained, my problem is just how to call this function from the main, avoiding providing an empty Map.
this is how I call the function now:
fibonacci(n, {});
But I would rather prefer to call it just like this:
fibonacci(n);
The canonical approach is to make memo optional, and use a fresh map if the memo argument is omitted. Because you want to change and update the map, you can't use a default value for the parameter, because default values must be constant, and constant maps are not mutable.
So, written very concisely:
int fibonacci(int n, [Map<int, int>? memo]) {
if (n <= 2) return 1;
return (memo ??= {})[n] ??= fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
}
The ??= operator assigns to the right-hand side if the value is null.
It's used both to initialize memo to a new map if the argument was omitted,
and to update the map if a cached value wasn't present.
I'd actually reconsider using a map. We know that the Fibonacci computation will compute a value for every prior number down to 1, so I'd just use a list instead:
int fibonacci(int n, [List<int?>? memo]) {
if (n <= 2) return 1;
return (memo ??= List<int?>.filled(n - 2))[n - 3] ??=
fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
}
That should work just like the map.
(I subtract 3 from n when doing the lookup because no value below 3 needs the list - it's handled by the prior if).
There are multiple ways to do it. This is my personal favorite, because it also limits the function that is only used for internal means and it doesn't have the need to check every recursion, as you already know there is a map provided:
int fibonacci(int n) {
return _fibonacci(n, {});
}
int _fibonacci(int n, Map<int, int> memo) {
if (n <= 2) return 1; // base case
final previouslyCalculated = memo[n]; // Memo check
if(previouslyCalculated != null) {
return previouslyCalculated;
}
// calculation
final next = _fibonacci(n - 1, memo) + _fibonacci((n - 2), memo);
memo[n] = next;
return next;
}
void main() {
print(fibonacci(4));
}
As Dart does not support overloading, if you actually need both versions to be publicly available (or want both private) you would have to pick different names.
Please note that I added proper types to your methods and cleaned them up a bit for everything that would not compile once proper types are used. Make sure you always use proper types and don't rely on dynamic to somehow works it's magic. The compiler can only help you, if you are explicit about what you want to do. Otherwise they can only nod and let you run into any mistake you may have made. Be smart, let your compiler help, it will catch a lot of errors for you at compile time that you would otherwise have to spent countless hours on debugging.
This is the solution I've found so far but looks very verbose and inelegant:
fibonacci(int n, [Map<int, int>? memo]) {
memo == null ? memo = {} : null; // null check
if (memo.containsKey(n)) return memo[n];
if (n <= 2) return 1;
memo[n] = fibonacci(n - 1, memo) + fibonacci((n - 2), memo);
return memo[n];
}
In this way I can call just:
fibonacci(n);

How to modify a functions internal variables at runtime and pass it to another function?

Functions in Dart are first-class objects, allowing you to pass them to other objects or functions.
void main() {
var shout = (msg) => ' ${msg.toUpperCase()} ';
print(shout("yo"));
}
This made me wonder if there was a way to modify a function a run time, just like an object, prior to passing it to something else. For example:
Function add(int input) {
return add + 2;
}
If I wanted to make the function a generic addition function, then I would do:
Function add(int input, int increment) {
return add + increment;
}
But then the problem would be that the object I am passing the function to would need to specify the increment. I would like to pass the add function to another object, with the increment specified at run time, and declared within the function body so that the increment cannot be changed by the recipient of the function object.
The answer seems to be to use a lexical closure.
From here: https://dart.dev/guides/language/language-tour#built-in-types
A closure is a function object that has access to variables in its
lexical scope, even when the function is used outside of its original
scope.
Functions can close over variables defined in surrounding scopes. In
the following example, makeAdder() captures the variable addBy.
Wherever the returned function goes, it remembers addBy.
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(int addBy) {
return (int i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
In the above cases, we pass 2 or 4 into the makeAdder function. The makeAdder function uses the parameter to create and return a function object that can be passed to other objects.
You most likely don't need to modify a closure, just the ability to create customized closures.
The latter is simple:
int Function(int) makeAdder(int increment) => (int value) => value + increment;
...
foo(makeAdder(1)); // Adds 1.
foo(makeAdder(4)); // Adds 2.
You can't change which variables a closure is referencing, but you can change their values ... if you an access the variable. For local variables, that's actually hard.
Mutating state which makes an existing closure change behavior can sometimes be appropriate, but those functions should be very precise about how they change and where they are being used. For a function like add which is used for its behavior, changing the behavior is rarely a good idea. It's better to replace the closure in the specific places that need to change behavior, and not risk changing the behavior in other places which happen to depend on the same closure. Otherwise it becomes very important to control where the closure actually flows.
If you still want to change the behavior of an existing global, you need to change a variable that it depends on.
Globals are easy:
int increment = 1;
int globalAdder(int value) => value + increment;
...
foo(globalAdd); // Adds 1.
increment = 2;
foo(globalAdd); // Adds 2.
I really can't recommend mutating global variables. It scales rather badly. You have no control over anything.
Another option is to use an instance variable to hold the modifiable value.
class MakeAdder {
int increment = 1;
int instanceAdd(int value) => value + increment;
}
...
var makeAdder = MakeAdder();
var adder = makeAdder.instanceAdd;
...
foo(adder); // Adds 1.
makeAdder.increment = 2;
foo(adder); // Adds 2.
That gives you much more control over who can access the increment variable. You can create multiple independent mutaable adders without them stepping on each other's toes.
To modify a local variable, you need someone to give you access to it, from inside the function where the variable is visible.
int Function(int) makeAdder(void Function(void Function(int)) setIncrementCallback) {
var increment = 1;
setIncrementCallback((v) {
increment = v;
});
return (value) => value + increment;
}
...
void Function(int) setIncrement;
int Function(int) localAdd = makeAdder((inc) { setIncrement = inc; });
...
foo(localAdd); // Adds 1.
setIncrement(2);
foo(localAdd); // Adds 2.
This is one way of passing back a way to modify the local increment variable.
It's almost always far too complicated an approach for what it gives you, I'd go with the instance variable instead.
Often, the instance variable will actually represent something in your model, some state which can meaningfully change, and then it becomes predictable and understandable when and how the state of the entire model changes, including the functions referring to that model.
Using partial function application
You can use a partial function application to bind arguments to functions.
If you have something like:
int add(int input, int increment) => input + increment;
and want to pass it to another function that expects to supply fewer arguments:
int foo(int Function(int input) applyIncrement) => applyIncrement(10);
then you could do:
foo((input) => add(input, 2); // `increment` is fixed to 2
foo((input) => add(input, 4); // `increment` is fixed to 4
Using callable objects
Another approach would be to make a callable object:
class Adder {
int increment = 0;
int call(int input) => input + increment;
}
which could be used with the same foo function above:
var adder = Adder()..increment = 2;
print(foo(adder)); // Prints: 12
adder.increment = 4;
print(foo(adder)); // Prints: 14

How to get variables that not declared yet but will declared soon?

How can I get variables that not declared yet?
Here are simple example:
a = b
b = 123
What I want from these 2 lines is a << 123. But obv it doesn't work.
I know the easy way to get the answer a = 123 is cut 1st line and paste it to lower than 2nd line.
But I'm in some problem. I need some function like 'WillDeclaredVar()' that I can use in like this:
a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)
so I can get the answer '123'.
Or there are any built-in functions that will allows me to do similar thing?
===
I think the link given by timrau is not telling my case. the key point is how to get Variables 'that not declared yet'.
===
Adding actual Code:
triggerCount = 0 -- Counting number of 'Trigger' function
local Trigger = function (t)
triggerCount = triggerCount + 1
return Trigger (t)
end
-- following Triggers are same as while statement.
-- following Triggers doing: Add 1 MarineCount until get 64000 MarineCount
Trigger { -- Here the Trigger function. Now triggerCount = 1.
players = {P1}
actions = {
SetDeaths(P1, Add, 1, "Terran Marine")
},
flag = {preserved},
}
Portal(LoopStart);
-- function Portal(VariableName) returns VariableName = triggerCount. So LoopStart = 1.
Trigger { -- Now triggerCount = 2.
players = {P1}
actions = {
LinkList(LoopEnd, LoopStart);
-- function LinkList(From, To) changes 'From' Trigger's next pointer to the 'To' Trigger.
-- But now the problem happens. Because 'LoopEnd' is not declared yet.
},
flag = {preserved},
}
Trigger { -- Now triggerCount = 3.
players = {P1}
conditions = {
Deaths(P1, Exactly, 64000, "Terran Marine");
}
actions = {
_LinkList(LoopEnd);
-- Reset LoopEnd's next pointer(= LoopEscape) if MarineCount hits 64000
},
flag = {preserved},
}
Portal(LoopEnd); -- LoopEnd = 3.
Changing Order of Triggers will break the Trigger logic(while statement).
All i want is get easy to coding. To put in bluntly, I don't need to solve this problem(get undeclared var). I can imagine a few ways to avoid it. But if i using these ways then the coding work will be very complicated and the difficulty of coding will increases greatly. The difficulty made me stop coding in recent months.
How can I get variables that not declared yet?
Short of time travel, you can't.
Your example code doesn't explain the motivation for the question, because this:
a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)
Can trivially be rearranged into this:
sheepCount = 123
b = sheepCount
a = WillDeclaredVar(b)
print(a)
It would be easier to answer your question if you showed the actual problem you're trying to solve (to avoid an XY problem).
However, as stated there are few things we can note.
First, you need to distinguish between declaring a variable and giving it a value. In Lua you can say:
local b
To declare b as a local variable, which presumably will make a slot for it in the stack frame and let you bind closures to it, before you give it a value. However, the line:
a = WillDeclaredVar(b)
Will pass WillDeclaredVar the value that b currently has, and there's no way for a to change retroactively as a result of b being assigned a new value. That's simply not going to happen, ever. Neither a nor WillDeclaredVar are even aware that b exists, they are receive the value it contains at the point of call.
You could however bind the variable b to a closure which will fetch b's current value when needed.
-- declare b before giving it a value, aka "forward reference"
local b
a = function() return b end
sheepCount = 123
b = sheepCount
print(a()) -- call a to get b's current value
Another way to do that would be to make b a global variable, which is really just a key into your environment table, so you could say:
a = WillDeclaredVar('b')
And have a be some object that can fetch the current value of __ENV['b'] when required.
However, neither of these will support this syntax:
print(a)
a needs to be a function, something that looks up the value of b when needed rather than simply holding a previously computed value. You could do it in this particular instance (i.e. a needs to be convertable to a string), by creating a proxy object that implements __tostring.
function WillDeclaredVar(variableName)
local proxy = { environment = _ENV or _G, variableName = variableName }
return setmetatable(proxy, {
__tostring = function(proxy)
return proxy.environment[proxy.variableName]
end
})
end
-- a will compute a value based on the current value of b when needed
a = WillDeclaredVar('b')
sheepCount = 123
b = sheepCount
print(a)
Output:
123
To make var1 be a reference for var2 write var1 = ReferenceF or var2 (please note a space inside "ReferenceFor"!)
do
local values, references, reference_flag = {}, {}
setmetatable(_G, {
__index = function (_, name)
if name == 'ReferenceF' then
reference_flag = true
elseif reference_flag then
reference_flag = false
return {[references] = name}
elseif references[name] then
return _G[references[name]]
else
return values[name]
end
end,
__newindex = function (_, name, val)
if type(val) == 'table' and val[references] then
references[name] = val[references]
else
values[name] = val
end
end
})
end
a = ReferenceF or b -- a is Reference For b
b = ReferenceF or c -- b is Reference For c
sheepCount = 123
c = sheepCount
print(a, b, c) --> 123 123 123

Hiding a Lua metatable and only exposing an object's attributes

How do you create a Lua object that only exposes its attributes and not its methods? For example:
local obj = {
attr1 = 1,
attr2 = 2,
print = function(...)
print("obj print: ", ...)
end,
}
Produces:
> for k,v in pairs(obj) do print(k, v) end
attr1 1
attr2 2
print function: 0x7ffe1240a310
Also, is it possible to not use the colon syntax for OOP in Lua? I don't need inheritance, polymorphism, only encapsulation and privacy.
I started out with the above question and after chasing down the rabbit hole, I was surprised by the limited number of examples, lack of examples for the various metamethods (i.e. __ipairs, __pairs, __len), and how few Lua 5.2 resources there were on the subject.
Lua can do OOP, but IMO the way that OOP is prescribed is a disservice to the language and community (i.e. in such a way as to support polymorphism, multiple inheritance, etc). There are very few reasons to use most of Lua's OOP features for most problems. It doesn't necessarily mean there's a fork in the road either (e.g. in order to support polymorphism there's nothing that says you have to use the colon syntax - you can fold the literature's described techniques in to the closure-based OOP method).
I appreciate that there are lots of ways to do OOP in Lua, but it's irritating to have there be different syntax for object attributes versus object methods (e.g. obj.attr1 vs obj:getAttr() vs obj.method() vs obj:method()). I want a single, unified API to communicate internally and externally. To that end, PiL 16.4's section on Privacy is a fantastic start, but it's an incomplete example that I hope to remedy with this answer.
The following example code:
emulates a class's namespace MyObject = {} and saves the object constructor as MyObject.new()
hides all of the details of the objects inner workings so that a user of an object only sees a pure table (see setmetatable() and __metatable)
uses closures for information hiding (see Lua Pil 16.4 and Object Benchmark Tests)
prevents modification of the object (see __newindex)
allows for methods to be intercepted (see __index)
lets you get a list of all of the functions and attributes (see the 'key' attribute in __index)
looks, acts, walks, and talks like a normal Lua table (see __pairs, __len, __ipairs)
looks like a string when it needs to (see __tostring)
works with Lua 5.2
Here's the code to construct a new MyObject (this could be a standalone function, it doesn't need to be stored in the MyObject table - there is absolutely nothing that ties obj once its created back to MyObject.new(), this is only done for familiarity and out of convention):
MyObject = {}
MyObject.new = function(name)
local objectName = name
-- A table of the attributes we want exposed
local attrs = {
attr1 = 123,
}
-- A table of the object's methods (note the comma on "end,")
local methods = {
method1 = function()
print("\tmethod1")
end,
print = function(...)
print("MyObject.print(): ", ...)
end,
-- Support the less than desirable colon syntax
printOOP = function(self, ...)
print("MyObject:printOOP(): ", ...)
end,
}
-- Another style for adding methods to the object (I prefer the former
-- because it's easier to copy/paste function()'s around)
function methods.addAttr(k, v)
attrs[k] = v
print("\taddAttr: adding a new attr: " .. k .. "=\"" .. v .. "\"")
end
-- The metatable used to customize the behavior of the table returned by new()
local mt = {
-- Look up nonexistent keys in the attrs table. Create a special case for the 'keys' index
__index = function(t, k)
v = rawget(attrs, k)
if v then
print("INFO: Successfully found a value for key \"" .. k .. "\"")
return v
end
-- 'keys' is a union of the methods and attrs
if k == 'keys' then
local ks = {}
for k,v in next, attrs, nil do
ks[k] = 'attr'
end
for k,v in next, methods, nil do
ks[k] = 'func'
end
return ks
else
print("WARN: Looking up nonexistant key \"" .. k .. "\"")
end
end,
__ipairs = function()
local function iter(a, i)
i = i + 1
local v = a[i]
if v then
return i, v
end
end
return iter, attrs, 0
end,
__len = function(t)
local count = 0
for _ in pairs(attrs) do count = count + 1 end
return count
end,
__metatable = {},
__newindex = function(t, k, v)
if rawget(attrs, k) then
print("INFO: Successfully set " .. k .. "=\"" .. v .. "\"")
rawset(attrs, k, v)
else
print("ERROR: Ignoring new key/value pair " .. k .. "=\"" .. v .. "\"")
end
end,
__pairs = function(t, k, v) return next, attrs, nil end,
__tostring = function(t) return objectName .. "[" .. tostring(#t) .. "]" end,
}
setmetatable(methods, mt)
return methods
end
And now the usage:
-- Create the object
local obj = MyObject.new("my object's name")
print("Iterating over all indexes in obj:")
for k,v in pairs(obj) do print('', k, v) end
print()
print("obj has a visibly empty metatable because of the empty __metatable:")
for k,v in pairs(getmetatable(obj)) do print('', k, v) end
print()
print("Accessing a valid attribute")
obj.print(obj.attr1)
obj.attr1 = 72
obj.print(obj.attr1)
print()
print("Accessing and setting unknown indexes:")
print(obj.asdf)
obj.qwer = 123
print(obj.qwer)
print()
print("Use the print and printOOP methods:")
obj.print("Length: " .. #obj)
obj:printOOP("Length: " .. #obj) -- Despite being a PITA, this nasty calling convention is still supported
print("Iterate over all 'keys':")
for k,v in pairs(obj.keys) do print('', k, v) end
print()
print("Number of attributes: " .. #obj)
obj.addAttr("goosfraba", "Satoshi Nakamoto")
print("Number of attributes: " .. #obj)
print()
print("Iterate over all keys a second time:")
for k,v in pairs(obj.keys) do print('', k, v) end
print()
obj.addAttr(1, "value 1 for ipairs to iterate over")
obj.addAttr(2, "value 2 for ipairs to iterate over")
obj.addAttr(3, "value 3 for ipairs to iterate over")
obj.print("ipairs:")
for k,v in ipairs(obj) do print(k, v) end
print("Number of attributes: " .. #obj)
print("The object as a string:", obj)
Which produces the expected - and poorly formatted - output:
Iterating over all indexes in obj:
attr1 123
obj has a visibly empty metatable because of the empty __metatable:
Accessing a valid attribute
INFO: Successfully found a value for key "attr1"
MyObject.print(): 123
INFO: Successfully set attr1="72"
INFO: Successfully found a value for key "attr1"
MyObject.print(): 72
Accessing and setting unknown indexes:
WARN: Looking up nonexistant key "asdf"
nil
ERROR: Ignoring new key/value pair qwer="123"
WARN: Looking up nonexistant key "qwer"
nil
Use the print and printOOP methods:
MyObject.print(): Length: 1
MyObject.printOOP(): Length: 1
Iterate over all 'keys':
addAttr func
method1 func
print func
attr1 attr
printOOP func
Number of attributes: 1
addAttr: adding a new attr: goosfraba="Satoshi Nakamoto"
Number of attributes: 2
Iterate over all keys a second time:
addAttr func
method1 func
print func
printOOP func
goosfraba attr
attr1 attr
addAttr: adding a new attr: 1="value 1 for ipairs to iterate over"
addAttr: adding a new attr: 2="value 2 for ipairs to iterate over"
addAttr: adding a new attr: 3="value 3 for ipairs to iterate over"
MyObject.print(): ipairs:
1 value 1 for ipairs to iterate over
2 value 2 for ipairs to iterate over
3 value 3 for ipairs to iterate over
Number of attributes: 5
The object as a string: my object's name[5]
Using OOP + closures is very convenient when embedding Lua as a facade or documenting an API.
Lua OOP can also be very, very clean and elegant (this is subjective, but there aren't any rules with this style - you always use a . to access either an attribute or a method)
Having an object behave exactly like a table is VERY, VERY useful for scripting and interrogating the state of a program
Is extremely useful when operating in a sandbox
This style does consume slightly more memory per object, but for most situations this isn't a concern. Factoring out the metatable for reuse would address this, though the example code above doesn't.
A final thought. Lua OOP is actually very nice once you dismiss most of the examples in the literature. I'm not saying the literature is bad, btw (that couldn't be further from the truth!), but the set of sample examples in PiL and other online resources lead you to using only the colon syntax (i.e. the first argument to all functions is self instead of using a closure or upvalue to retain a reference to self).
Hopefully this is a useful, more complete example.
Update (2013-10-08): There is one notable drawback to the closure-based OOP style detailed above (I still think the style is worth the overhead, but I digress): each instance must have its own closure. While this is obvious in the above lua version, this becomes slightly problematic when dealing with things on the C-side.
Assume we're talking about the above closure style from the C-side from here on out. The common case on the C side is to create a userdata via lua_newuserdata() object and attach a metatable to the userdata via lua_setmetatable(). On face value this doesn't appear like a problem until you realize that methods in your metatable require an upvalue of the userdata.
using FuncArray = std::vector<const ::luaL_Reg>;
static const FuncArray funcs = {
{ "__tostring", LI_MyType__tostring },
};
int LC_MyType_newInstance(lua_State* L) {
auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
new(userdata) MyType();
// Create the metatable
lua_createtable(L, 0, funcs.size()); // |userdata|table|
lua_pushvalue(L, -2); // |userdata|table|userdata|
luaL_setfuncs(L, funcs.data(), 1); // |userdata|table|
lua_setmetatable(L, -2); // |userdata|
return 1;
}
int LI_MyType__tostring(lua_State* L) {
// NOTE: Blindly assume that upvalue 1 is my userdata
const auto n = lua_upvalueindex(1);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}
Note how the table created with lua_createtable() didn't get associated with a metatable name the same as if you would have registered the metatable with luaL_getmetatable()? This is 100% a-okay because these values are completely inaccessible outside of the closure, but it does mean that luaL_getmetatable() can't be used to look up a particular userdata's type. Similarly, this also means that luaL_checkudata() and luaL_testudata() are also off limits.
The bottom line is that upvalues (such as userdata above) are associated with function calls (e.g. LI_MyType__tostring) and are not associated with the userdata itself. As of now, I'm not aware of a way in which you can associate an upvalue with a value such that it becomes possible to share a metatable across instances.
UPDATE (2013-10-14) I'm including a small example below that uses a registered metatable (luaL_newmetatable()) and also lua_setuservalue()/lua_getuservalue() for a userdata's "attributes and methods". Also adding random comments that have been the source of bugs/hotness that I've had to hunt down in the past. Also threw in a C++11 trick to help with __index.
namespace {
using FuncArray = std::vector<const ::luaL_Reg>;
static const std::string MYTYPE_INSTANCE_METAMETHODS{"goozfraba"}; // I use a UUID here
static const FuncArray MyType_Instnace_Metamethods = {
{ "__tostring", MyType_InstanceMethod__tostring },
{ "__index", MyType_InstanceMethod__index },
{ nullptr, nullptr }, // reserve space for __metatable
{ nullptr, nullptr } // sentinel
};
static const FuncArray MyType_Instnace_methods = {
{ "fooAttr", MyType_InstanceMethod_fooAttr },
{ "barMethod", MyType_InstanceMethod_barMethod },
{ nullptr, nullptr } // sentinel
};
// Must be kept alpha sorted
static const std::vector<const std::string> MyType_Instance___attrWhitelist = {
"fooAttr",
};
static int MyType_ClassMethod_newInstance(lua_State* L) {
// You can also use an empty allocation as a placeholder userdata object
// (e.g. lua_newuserdata(L, 0);)
auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
new(userdata) MyType(); // Placement new() FTW
// Use luaL_newmetatable() since all metamethods receive userdata as 1st arg
if (luaL_newmetatable(L, MYTYPE_INSTANCE_METAMETHODS.c_str())) { // |userdata|metatable|
luaL_setfuncs(L, MyType_Instnace_Metamethods.data(), 0); // |userdata|metatable|
// Prevent examining the object: getmetatable(MyType.new()) == empty table
lua_pushliteral(L, "__metatable"); // |userdata|metatable|literal|
lua_createtable(L, 0, 0); // |userdata|metatable|literal|table|
lua_rawset(L, -3); // |userdata|metatable|
}
lua_setmetatable(L, -2); // |userdata|
// Create the attribute/method table and populate with one upvalue, the userdata
lua_createtable(L, 0, funcs.size()); // |userdata|table|
lua_pushvalue(L, -2); // |userdata|table|userdata|
luaL_setfuncs(L, funcs.data(), 1); // |userdata|table|
// Set an attribute that can only be accessed via object's fooAttr, stored in key "fooAttribute"
lua_pushliteral(L, "foo's value is hidden in the attribute table"); // |userdata|table|literal|
lua_setfield(L, -2, "fooAttribute"); // |userdata|table|
// Make the attribute table the uservalue for the userdata
lua_setuserdata(L, -2); // |userdata|
return 1;
}
static int MyType_InstanceMethod__tostring(lua_State* L) {
// Since we're using closures, we can assume userdata is the first value on the stack.
// You can't make this assumption when using metatables, only closures.
luaL_checkudata(L, 1, MYTYPE_INSTANCE_METAMETHODS.c_str()); // Test anyway
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, 1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}
static int MyType_InstanceMethod__index(lua_State* L) {
lua_getuservalue(L, -2); // |userdata|key|attrTable|
lua_pushvalue(L, -2); // |userdata|key|attrTable|key|
lua_rawget(L, -2); // |userdata|key|attrTable|value|
if (lua_isnil(L, -1)) { // |userdata|key|attrTable|value?|
return 1; // |userdata|key|attrTable|nil|
}
// Call cfunctions when whitelisted, otherwise the caller has to call the
// function.
if (lua_type(L, -1) == LUA_TFUNCTION) {
std::size_t keyLen = 0;
const char* keyCp = ::lua_tolstring(L, -3, &keyLen);
std::string key(keyCp, keyLen);
if (std::binary_search(MyType_Instance___attrWhitelist.cbegin(),
MyType_Instance___attrWhitelist.cend(), key))
{
lua_call(L, 0, 1);
}
}
return 1;
}
static int MyType_InstanceMethod_fooAttr(lua_State* L) {
// Push the uservalue on to the stack from fooAttr's closure (upvalue 1)
lua_pushvalue(L, lua_upvalueindex(1)); // |userdata|
lua_getuservalue(L, -1); // |userdata|attrTable|
// I haven't benchmarked whether lua_pushliteral() + lua_rawget()
// is faster than lua_getfield() - (two lua interpreter locks vs one lock + test for
// metamethods).
lua_pushliteral(L, "fooAttribute"); // |userdata|attrTable|literal|
lua_rawget(L, -2); // |userdata|attrTable|value|
return 1;
}
static int MyType_InstanceMethod_barMethod(lua_State* L) {
// Push the uservalue on to the stack from barMethod's closure (upvalue 1)
lua_pushvalue(L, lua_upvalueindex(1)); // |userdata|
lua_getuservalue(L, -1); // |userdata|attrTable|
// Push a string to finish the example, not using userdata or attrTable this time
lua_pushliteral(L, "bar() was called!"); // |userdata|attrTable|literal|
return 1;
}
} // unnamed-namespace
The lua script side of things looks something like:
t = MyType.new()
print(typue(t)) --> "userdata"
print(t.foo) --> "foo's value is hidden in the attribute table"
print(t.bar) --> "function: 0x7fb560c07df0"
print(t.bar()) --> "bar() was called!"
how do you create a lua object that only exposes its attributes and not its methods?
If you don't expose methods in any way, you can't call them, right? Judging from your example, it sounds like what you really want is a way to iterate through the attributes of an object without seeing methods, which is fair.
The simplest approach is just to use a metatable, which puts the methods in a separate table:
-- create Point class
Point = {}
Point.__index = Point
function Point:report() print(self.x, self.y) end
-- create instance of Point
pt = setmetatable({x=10, y=20}, Point)
-- call method
pt:report() --> 10 20
-- iterate attributes
for k,v in pairs(pt) do print(k,v) end --> x 10 y 20
is it possible to not use the colon syntax for OOP in Lua?
You can use closures instead, but then pairs is going to see your methods.
function Point(x, y)
local self = { x=x, y=y}
function pt.report() print(self.x, self.y) end
return self
end
pt = Point(10,20)
pt.report() --> 10 20
for k,v in pairs(pt) do print(k,v) end --> x 10 y 20 report function: 7772112
You can fix the latter problem by just writing an iterator that shows only attributes:
function nextattribute(t, k)
local v
repeat
k,v = next(t, k)
if type(v) ~= 'function' then return k,v end
until k == nil
end
function attributes (t)
return nextattribute, t, nil
end
for k,v in attributes(pt) do print(k,v) end --> x 10 y 20
I don't need inheritance, polymorphism
You get polymorphism for free in Lua, without or without classes. If your zoo has a Lion, Zebra, Giraffe each of which can Eat() and want to pass them to the same Feed(animal) routine, in a statically typed OO languages you'd need to put Eat() in a common base class (e.g. Animal). Lua is dynamically typed and your Feed routine can be passed any object at all. All that matters is that the object you pass it has an Eat method.
This is sometimes called "duck typing": if it quacks like a duck and swims like a duck, it's a duck. As far as our Feed(animal) routine is concerned, if it Eats like an animal, it's an animal.
only encapsulation and privacy.
Then I think exposing data members while hiding methods is the opposite of what you want to do.

Weird result comparing property values using reflection

Can someone explain why this is occurring? The code below was executed in the immediate window in vs2008. The prop is an Int32 property (id column) on an object created by the entity framework.
The objects entity and defaultEntity were created using Activator.CreateInstance();
Convert.ChangeType(prop.GetValue(entity, null), prop.PropertyType)
0
Convert.ChangeType(prop.GetValue(defaultEntity, null), prop.PropertyType)
0
Convert.ChangeType(prop.GetValue(entity, null), prop.PropertyType) == Convert.ChangeType(prop.GetValue(defaultEntity, null), prop.PropertyType)
false
I assume you're wondering why the third line prints false. If you want to know why the first two lines are printing 0, you'll have to post more code and tell us what you actually expected.
Convert.ChangeType returns object. Therefore when the property type is actually Int32 it will return a boxed integer.
Your final line is comparing the references of two boxed values. Effectively you're doing:
object x = 0;
object y = 0;
Console.WriteLine (x == y); // Prints False
You can use Equals instead - and the static object.Equals method handily copes with null references, should that be an issue:
object x = 0;
object y = 0;
Console.WriteLine (object.Equals(x, y)); // Prints True

Resources