I recently looked up an example of simple Lua oop principles and modified it slightly, as seen below.
What I find trouble comprehending is the connection between elf.name and hobbit.name. Why is it that when I change the value of either, that it affects the other? I am aware that I could have set elf.name as local inside the function, but it wouldn't have had the same effect.
In contrast, changing the value of another.name has no effect on the other two. Is there a lasting connection between elf.name and hobbit.name? I thought they were treated as separate objects.
Thanks.
;^)
Zalokin
elf = {}
elf.name = "Frodo"
another = {}
function Character()
return elf
end
local hobbit = Character()
print ("elf.name set to Frodo")
print("hobbit.name - "..hobbit.name)
print("elf.name - "..elf.name.."\
")
hobbit.name = "Charlie"
print ("hobbit.name set to Charlie")
print("hobbit.name - "..hobbit.name)
print("elf.name - "..elf.name.."\
")
another.name = "Gary"
print ("hobbit.name set to Charlie and another.name set to Gary")
print("hobbit.name - "..hobbit.name)
print("elf.name - "..elf.name)
print("another.name - "..another.name.."\
")
Result: -
>>>>elf.name set to Frodo
>>>>hobbit.name - Frodo
>>>>elf.name - Frodo
>>>>
>>>>hobbit.name set to Charlie
>>>>hobbit.name - Charlie
>>>>elf.name - Charlie
>>>>
>>>>hobbit.name set to Charlie and another.name set to Gary
>>>>hobbit.name - Charlie
>>>>elf.name - Charlie
>>>>another.name - Gary
Any use of {}, is known as a table constructor. It creates a whole new table. When you do elf.name = "Frodo", you're modifying the table that elf points to. In your code, elf and another are initialized separately. On the other hand, hobbit is indirectly given a reference to elf. In other words, elf and hobbit are references to the same table.
function Character()
return elf
end
local hobbit = Character()
That's what you are wrong at. I belive lua is pass-by-reference. This way, your code doesn't work. Also, Hobbit shouldn't be instance of Elf - if Lua is pass-by-reference its natural that instances will share data. Also, at top elf's name is Frodo. I recommend you to remove it. All you need to do is do this like you did with another object.
EDIT: Lua IS pass-by-reference but only on tables and objects.
Quoting Lua 5.1 Reference Manual:
There are eight basic types in Lua: nil, boolean, number, string,
function, userdata, thread, and table. ....
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only
references to them. Assignment, parameter passing, and function
returns always manipulate references to such values; these operations
do not imply any kind of copy.
Related
I have been playing with Lua for the past week and I ended up writing this peace of code. I find it really useful that you can dynamically create new functions that "inherit" other functions, so programmers must have a name for it. My questions are:
What is this called?
Is there a better way to do this? (cycle over a data structure and create add-on functions that "improve" existing functions)
D = {
name = {
value = nil,
offset = 0,
update = function (self)
self.value = "Berlin"
end,
},
}
--Dynamic function definition
for i in pairs(D) do
D[i].upAndWrite = function(self)
self:update()
print("upAndWrite was here")
end
end
print(D.name.value)
D.name:upAndWrite()
print(D.name.value)
Result:
nil
upAndWrite was here
Berlin
I don't think that what you're doing have special name for it, it's just on-the-fly function creation.
There are few notes regarding your code:
Proper for loop
for i in pairs(D) do
…
end
In programming, variable i is generally used for counter loops, like in
for i=1,100 do
…
end
Here, pairs returns an iterator function and the idiomatic way to use it is
for k,v in pairs(D) do
…
end
Here k is a key (like i in your code) and v is a value (use it instead of indexing table like D[k] or D[i] in your code when you need to access the corresponding value).
There's no need to create functions on the fly!
Another important thing is that you create new function on each loop iteration. While this feature is very powerful, you're not using it at all as you don't store anything using upvalues and only access data through arguments.
A better way to do it would be creating function once and assigning it to every field:
-- Define D here
do
local function upAndWrite(self)
self:update()
print("upAndWrite was here")
end
for k,v in pairs(D) do
v.upAndWrite = upAndWrite -- Use our function
end
end
-- Perform tests here
What does on-the-fly function creation allow?
As mentioned above, you can utilize this very powerful mechanism of closures in certain situations. Here's a simple example:
local t = {}
for i = 1, 100 do
-- Create function to print our value
t[i] = function() print(i) end
-- Create function to increment value by one
t[-i] = function() i=i+1 end
end
t[1]() -- Prints 1
t[20]() -- Prints 20
t[-20]() -- Increment upvalue by one
t[20]() -- Now it is 21!
This example demonstrates one possible usage of upvalues and the fact that many functions can share them. This can be useful in a variety of situations together with the fact that upvalues can't be changed by side code (without use of debug library) and can be trusted in general.
I hope my answer covers what you wanted to know.
Note: Also, this language is called Lua, not LUA.
As a whole it doesn't have a name, no. There's lots of concepts that play into this:
First Class Functions aka. functions that can be assigned to variables and passed around just like numbers or strings.
Anonymous Functions aka. functions that are created without giving it a name explicitly. All functions in Lua are technically anonymous, but often they are assigned into a variable right after creation.
Metaprogramming aka. writing programs that write programs. A loop that creates functions (or methods) on an arbitrary number of objects is very simple, but I'd count it as metaprogramming.
Lua Tables; this may seem obvious, but consider that not all languages have a feature like this. Javascript has objects which are similar, but Ruby for example has no comparable feature.
If you're gonna use pairs, you might as well make use of both variables.
for key, object in pairs(D) do
function object:upAndWrite(self)
self:update()
print("upAndWrite was here")
end
end
Though that would create many closures, which means more work for the garbage collector, more memory usage and slower execution speed.
for key, object in pairs(D) do
print(object.upAndWrite) -- All the functions are different
end
It's a good first stage, but after refactoring it a bit you could get this:
do
local method = function(self) -- Create only one closure
self:update()
print("upAndWrite was here")
end
for key, object in pairs(D) do
object.upAndWrite = method -- Use single closure many times
end
end
Now there's only one closure that's shared among all the tables.
for key, object in pairs(D) do
print(object.upAndWrite) -- All the functions are the same
end
I have a simple example model where I would like to generate names for the objects of the Position rule that were not given a name with as <NAME>. This is needed so that I can find them later with the built-in FQN scope provider.
My idea would be to do this in the position_name_generator object processor but that will be only be called after the whole model is parsed. I don´t really understand the reason for that, since by the time I would need a Position object in the Project, the objects are already created, still the object processor will not be called.
Another idea would be to do this in a custom scope provider for Position.location which would then first do the name generation and then use the built-in FQN to find the Location object. Although this would work, I consider this hacky and I would prefer to avoid it.
What would be the textX way of solving this issue?
(Please take into account that this is only a small example. In reality a similar functionality is required for a rather big and complex model. To change this behaviour with the generated names is not possible since it is a requirement.)
import textx
MyLanguage = """
Model
: (locations+=Location)*
(employees+=Employee)*
(positions+=Position)*
(projects+=Project)*
;
Project
: 'project' name=ID
('{'
('use' use=[Position])*
'}')?
;
Position
: 'define' 'position' employee=[Employee|FQN] '->' location=[Location|FQN] ('as' name=ID)?
;
Employee
: 'employee' name=ID
;
Location
: 'location' name=ID
( '{'
(sub_location+=Location)+
'}')?
;
FQN
: ID('.' ID)*
;
Comment:
/\/\/.*$/
;
"""
MyCode = """
location Building
{
location Entrance
location Exit
}
employee Hans
employee Juergen
// Shall be referred to with the given name: "EntranceGuy"
define position Hans->Building.Entrance as EntranceGuy
// Shall be referred to with the autogenerated name: <Employee>"At"<LastLocation>
define position Juergen->Building.Exit
project SecurityProject
{
use EntranceGuy
use JuergenAtExit
}
"""
def position_name_generator(obj):
if "" == obj.name:
obj.name = obj.employee.name + "At" + obj.location.name
def main():
meta_model = textx.metamodel_from_str(MyLanguage)
meta_model.register_scope_providers({
"Position.location": textx.scoping.providers.FQN(),
})
meta_model.register_obj_processors({
"Position": position_name_generator,
})
model = meta_model.model_from_str(MyCode)
assert model, "Could not create model..."
if "__main__" == __name__:
main()
What is the textx way to solve this...
The use case you describe is to define the name of an object based on other model elements, including a reference to other model elements. This is currently not part of any test and use cases included in our test suite and the textx docu.
Object processors are executed at defined stages during model construction (see http://textx.github.io/textX/stable/scoping/#using-the-scope-provider-to-modify-a-model). In the described setup they are executed after reference resolution. Since the name to be defined/deduced itself is required for reference resolution, object processors cannot be used here (even if we allow to control when object processors are executed, before or after scope resolution, the described setup still will not work).
Given the dynamics of model loading (see http://textx.github.io/textX/stable/scoping/#using-the-scope-provider-to-modify-a-model), the solution is located within a scope provider (as you suggested). Here, we allow to control the order of reference resolution, such that references to the object being named by a custom procedure are postponed, until references required to deduce/define the name resolved.
Possible workaround
A preliminary sketch of how your use case can be solved is discussed in a https://github.com/textX/textX/pull/194 (with an attached issue https://github.com/textX/textX/issues/193). This textx PR contains a version of scoping.py you could probably use for your project (just copy and rename the module). A full-fledged solution could be part of the textx TEP-001, where we plan to make scoping more controllable to the end-user.
Playing around with this absolutely interesting issue revealed new aspects to me for the textx framework.
names dependent on model contents (involving unresolved references). This name resolution, which can be Postponed (in the referenced PR, see below), in terms of our reference resolution logic.
Even more interesting are the consequences of that: What happens to references pointing to locations, where unresolved names are found? Here, we must postpone the reference resolution process, because we cannot know if the name might match when resolved...
Your example is included: https://github.com/textX/textX/blob/analysis/issue193/tests/functional/test_scoping/test_name_resolver/test_issue193_auto_name.py
It seems that, as w/ Inductive and Fixpoint, you can mutually define Function's w/ with. Can you give the syntax and/or an example of this? I couldn't find anything anywhere. I suppose it's the same as for Fixpoint
(found nothing on this either). A non-working (but half-compiling -- the 2 last lines highlight in red) example:
Variable ARG:Type.
Variable phy inf phyinf: ARG.
Function Phy (x:ARG): ARG := match x with Inf x => phyinf | _ => phy end
with Inf (x:ARG): ARG := match x with Phy x => phyinf | _ => inf end. (*Error: Unknown constructor: Inf.*)
Alright, I think I finally understood your question.
There is indeed a way to mutually define several Fixpoint. It is (lightly) documented in the variant section here.
Similarly, there is a way to mutually define several Inductive types (documented here).
And there is a way to mutually define several Function. Note however the remark that the manual makes about this feature:
The Function construction enjoys also the with extension to define mutually recursive definitions. However, this feature does not work for non structural recursive functions.
The error that you are getting in your half-working example is not about syntax though, neither is it related to the Function ... with feature. The error is that you can only use pattern-matching on inductive types and branches must start with a constructor. In your example, ARG is not an inductive type and Inf is not a constructor. I can't really "correct" your example as I don't really see what you were trying to express. Was this example made just for this question? In this case, you stripped it down to too little.
PS: I wonder if somehow, you were trying to do induction-recursion (definining at the same time a recursive function and an inductive type). If this were the case, then no luck: Coq does not have this feature yet.
So I'm just starting to learn Eiffel. One of the first exercises in the book I'm using says to make a function that does base^exp without using ^. I've copied my code below.
class
APPLICATION
inherit
ARGUMENTS
create
make
feature {NONE} -- Initialization
make
-- Run application.
do
create power(2;3)
printf("2 to the power of 3 is " + answer)
end
power(base : REAL; exp : INTEGER) : REAL
-- computers base raised to the bower of exp without using ^
local
remain : INTEGER
do
remain := exp
if remain = 0 then
result := 1
else
from
until
remain = 0
loop
result := result * result
remain := remain -1
end
end
end
end
How do I use this? Do I need it on the same level as feature{NONE}'s make? I know how I'm calling it is wrong, and I can't find anything in the chapter I just read, or online on how to pass parameters into it or how to use it's results.
There are several issues with the original code:
create is used to create an object, but you are not going to create anything, but to get a result of a computation of the function power by calling it. Therefore the keyword create is not needed.
You are using an entity answer to report the result of evaluation on a screen. However it is not declared anywhere. I believe the proper place would be a local variable declaration section.
The entity answer is not initialized to the result of the function power. This is usually done by an assignment instruction.
Feature arguments are separated by a comma, not by a semicolon.
From the original code it's unclear what is the type of the variable answer. Assuming it matches the type of the function power, before adding it to a string, it needs to be converted to a string. This is done by calling the feature out.
The standard feature for printing a string to a console is print, not printf.
Combining the critical points above, we get
make
-- Run application.
local
answer: REAL
do
answer := power(2, 3)
print ("2 to the power of 3 is " + answer.out)
end
After that the code can be compiled. Now less critical points:
It is a good style to put features to a dedicated feature clauses, so I would add a line like feature -- Basic operations before the feature power.
The implementation of the feature power has at least two problems. I'm not going to detail them here, but would give two hints instead:
by default numeric Result is initialized to 0, this needs to be taken into account for operations that use it without first assigning any other value
even though an argument base is passed to the function power it remains unused in the original version of the code
I am new to Stata and macros.
I am trying to loop over several variables to generate estimates from the mlogit command and then save them in datasets. That portion is working well.
The problem I have is a categorical variable that I need to split into dummy variables:
global mypath "/Volumes/NO NAME/Dissertation/Data/AIM 2"
use "$mypath/AIM 2 DATA"
global SES "sesq2 sesq3 sesq4 sesq5"
/*regression*/
foreach xvar in age_median female marital ethnicity literacy $SES poor_health physical_median mental_median facility_fee time_clinic {
mlogit trauma_main `xvar', b(5) vce(cluster ea_id) rrr
parmest, saving("$mypath/multi_`xvar'.dta", replace)
}
I thought that by setting SES as a global variable, the loop would treat that as one set of variables, but I was mistaken. The code loops over every variable in $SES so I end up with each dummy variable regressed onto trauma_main separately, which is not what I want.
Is there a way to "tell" Stata to treat the dummy variables as one block? Additionally, I know that I could do i.SES and using that does work fine, but the reference group that is used is not the one that I want. I have googled how to set the reference group for something like i.var, but I am coming up with nothing useful, likely because I am using the wrong search terms.
Thank you in advance for any advice.
Maggie
You do not need to split your categorical variable into dummies. You can use the factor variables notation (i.) instead. This is documented in help fvvarlist. With factor variables, a change of the reference category is straightforward.
Here is an example. The site variable has three categories. By default site = 1 is the reference category for the categorical variable:
webuse sysdsn1, clear
foreach v in age male i.site {
mlogit insure `v'
}
With ib you can set the reference category to any desired level. If you want site = 2 as the reference, you can do the following:
foreach v in age male ib2.site {
mlogit insure `v'
}
Stata's documentation for the foreach command indicates that it would work without the global macro, i.e.
. foreach xvar in age_median female marital ethnicity literacy "sesq2 sesq3 sesq4 sesq5" poor_health physical_median mental_median facility_fee time_clinic {
If you want to do it using a global macro, you'll need to use compound double-quotes to define a macro that includes quote marks:
. global SES `""sesq2 sesq3 sesq4 sesq5""'