Home » Archived » Lua Development Tools » How to document inherit relation
How to document inherit relation [message #1229396] |
Thu, 09 January 2014 06:01  |
Eclipse User |
|
|
|
Hi, all
I have tried to make an Execution Environment for cocos2d-x,and it's all ok now except for inherit. For example, CCAtion is parent of CCActionEase, but I can't get any support from CCAtion when I type CCActionEase. So how to express inherit reletionship in ldt? Thanks
|
|
| | | | |
Re: How to document inherit relation [message #1230514 is a reply to message #1229923] |
Sun, 12 January 2014 02:39   |
Eclipse User |
|
|
|
I also don't know how to make types like that work. How would you make doumentation for this?
Position = {meta = {}}
setmetatable(Position, Position.meta)
function Position.meta:__call(x, y, z)
local t = {x = x, y = y, z = z}
return setmetatable(t, {__index = Position})
end
function Position:toString()
return "{" .. "x = " .. self.x .. ", y = " .. self.y .. ", z = " .. self.z .."}"
end
local s = Position(32, 32, 32)
print(s:toString())
|
|
| |
Re: How to document inherit relation [message #1231015 is a reply to message #1230764] |
Mon, 13 January 2014 11:05   |
Eclipse User |
|
|
|
@Hoping: Glad you fix your problem. When you think your EE is ready feel free to contribute it to the following page: http://wiki.eclipse.org/Koneki/LDT/User_Area/Available_Execution_Environments
@Abe: The metatable field "__call" is not supported by the documentation. You need to create a function to see it in the auto-completion.
Also, too have autocompletion on a new variable you need to affect it a type.
See this sample in the documentation.
So for example auto-completion on your sample you need to modify a bit the code to look like that:
--- @type position
local position = {x = 0, y = 0, z = 0} -- initialize the type
--- @function
-- @return #position
function position.new(x, y, z)
local t = {x = x, y = y, z = z}
return setmetatable(t, {__index = position})
end
function position:toString()
return "{" .. "x = " .. self.x .. ", y = " .. self.y .. ", z = " .. self.z .."}"
end
local s = position.new()
s:toString()
As you see, you need to create a type and then to specify the return value of the new fonction as the created type.
|
|
| | | |
Re: How to document inherit relation [message #1262369 is a reply to message #1257605] |
Mon, 03 March 2014 10:09   |
Eclipse User |
|
|
|
Thanks Simon!
After further investigation, I found a workaround (and have now a fully functioning execution environment): the trick is to take advantage of ---@type's "implicit scoping" (implicit as we can't have [parent=#something] in a type declaration) within its file or module. Then that type can be referred to from a *different* file where the .metatable:__call function is documented (with the same name of the type).
Using the example from @Abe:
-- file Position.lua
Position = {meta = {}} -- #Position
setmetatable(Position, Position.meta)
function Position.meta:__call(x, y, z)
local t = {x = x, y = y, z = z}
return setmetatable(t, {__index = Position})
end
function Position:toString()
return "{" .. "x = " .. self.x .. ", y = " .. self.y .. ", z = " .. self.z .."}"
end
-- file main.lua
---@function [parent=#global] Position
--@param x
--@param y
--@param z
--@return Position#Position a position instance
require('Position') -- this isn't necessary (or even allowed) in Codea
local s = Position(32, 32, 32)
print(s:toString()) -- autocompletion works
This workaround, while satisfactory for building an execution environment, is still less than ideal in daily use, given that changing a __call constructor requires edits in two separate files!
It seems a tall order, but would it be possible to allow arbitrary scoping of everything using the classic dot notation? Although I'm sure there must be hundreds of reasons that make this a really bad idea.
EDIT: what I'm trying to get at is this: if we allow the idea that everything - in this case, functions - is a type (everything is a table!), then everything should be scoped in a straightforward way. As another example, take the tween.lua library used in Codea:
tween = {}
tween.start = function()... -- it doesn't even return a normal instance but just an id, as it's more like a collection singleton keeping its "instances" internally
tween.delay = function()...
tween.meta:__call = function(...) tween.start(...) end
tween.easing = {}
tween.easing.cubicInOut = function()...
-- etc
If everything is a type, then "tween()" is a function - and also a type. "easing" is a type with parent=#tween. etc.
[Updated on: Mon, 03 March 2014 10:32] by Moderator
|
|
|
Re: How to document inherit relation [message #1268530 is a reply to message #1262369] |
Mon, 10 March 2014 12:29   |
Eclipse User |
|
|
|
Here some tips about your exemple, but you still have two files to edit.
In the Position.lua you should explicit the type declaration by adding a @type annotation instead to type your variable using "-- #Position" (which create a implicit type).
You should put the Position constructor function declaration in the global.lua file your Codea Execution Environment as this function is global and seems to be pre-loaded by the Codea framework. See the note about globals in the following documentation: https://wiki.eclipse.org/Koneki/LDT/User_Area/Execution_Environment_file_format.
So in the main.lua file autocompletion works on both contructor and methods.
Here the files:
-- file Position.lua
--- @type
Position = {meta = {}}
setmetatable(Position, Position.meta)
function Position.meta:__call(x, y, z)
local t = {x = x, y = y, z = z}
return setmetatable(t, {__index = Position})
end
function Position:toString()
return "{" .. "x = " .. self.x .. ", y = " .. self.y .. ", z = " .. self.z .."}"
end
-- file global.lua
---@function [parent=#global] Position
--@param x
--@param y
--@param z
--@return Position#Position a position instance
-- file main.lua
local s = Position(32, 32, 32) -- autocompletion works
print(s:toString()) -- autocompletion works
About the "scoping" stuff, the concept of "parent" is only used by functions and field to attach them to a type. As you say a type is always implementing by a lua table and tables have no consider about their parents so i don't get the point to add this concept to a table. Declaring tween as a type let you have auto completion on his subtable such as "easing".
Be aware that in the notation "Postion#Position" the first "Position" is the module (i.e. file) name (not his parent) and the second one is the type name.
Maybe you can explain what problem this scoping should fix ?
Marc
|
|
|
Re: How to document inherit relation [message #1278771 is a reply to message #1268530] |
Thu, 27 March 2014 16:35   |
Eclipse User |
|
|
|
Marc, thanks for the response.
Let me try again to explain what I mean: I'm not saying to allow types to have a parent; I'm saying to make everything a type (while probably still leaving the option of explicitly declaring "abstract" types).
Before I continue:
Quote:Maybe you can explain what problem this scoping should fix ?
And the answer would be
Quote:The metatable field "__call" is not supported by the documentation.
But, instead of treating it as a special case...
Quote:You're right, we should definitely support that. (https://bugs.eclipse.org/bugs/show_bug.cgi?id=429170)
...I'm suggesting to have a discussion on whether it's possible (and sensible) to find a more generalized solution.
In the tween example, even once (if) it becomes possible to declare the __call, I'd still have to jump through needless hoops:
---@function tween
--@param ...
---@type type_tween
---@field [parent=#global] #type_tween tween
---@function delay [parent=#type_tween]
--@param ...
whereas I'd want the example in my previous post to be self-documenting.
Moreover, the way to *document* (as opposed to have them inferred from code) subtables (such as tween.easing), from what I understand, seems to be:
---@type sometype
---@type sometype.subtable
---@field [parent=#sometype] #sometype.subtable subtable
---@field [parent=#sometype.subtable] subfield
which shows in the outline sometype and sometype.subtable as siblings (because, no subtypes!) But isn't this a rather clear case of subtable being a type whose parent is sometype? The fact that such constructs are even allowed to begin with seems to prove it, but this "syntactic sugar" seems unnecessarily verbose (and even imprecise with respect to the way the code is actually structured). I don't understand why you say that tables (/types) have no concept of a parent.
But! - you say - if subtypes were allowed, we would then have
---@type sometype
---@type [parent=#sometype] subtable
---@field [parent=#sometype] #sometype.subtable subfield
---@field [parent=#sometype.subtable] subfield
which is just as verbose and even *more* confusing. Which is why my suggestion is (again) to make everything a type, as opposed to allow [parent] in types, so that we'd simply have
---@type sometype (This one we'll leave as *explicit* abstract type - there's no global singleton for it)
--@field subtable (this is also a type)
---@field [parent=#sometype.subtable] subfield
which I'd further simplify using the classic dot notation (from where to infer parenthood relationships):
---@type sometype
---@field sometype.subtable
---@field sometype.subtable.subfield
--------------
Another, completely different way of seeing the issue (it's *very* hard to describe it effectively, please bear with me) is this: the current luadocumentor specification "forces" an OOP-like approach onto one's documentation (and therefore code).
OOP-like because of the distinction between @type ("class") and @field or whatever ("instance"). But Lua doesn't want to be constricted into any specific paradigm! The module system (which luadocumentor models) is a *suggestion*, but it's seen (by luadocumentor) as the One True Way (which it isn't, as proven for example by the mere existence of Codea).
For example, Lua allows me to do something like this:
dsl = setmetatable({},{
__call = function() return crazystuff() end
__index = function(t,k)
if k=='key1' then dosomething()
elseif key=='key2' then dosomethingelse() end
end
__newindex = function(t,k,v)
if k=='case1' then dostuff() v(somearg)
elseif k=='case2' then domorestuff() v(otherarg) end
end
})
which I'd want to document like this (again, I substituted the [parent=] syntax with the "classic dot notation" I mentioned in my previous post):
---@function dsl
--@return #sometype some crazy stuff
dsl = setmetatable({},{
__call = function() return crazystuff() end
__index = function(t,k)
---@function dsl.key1
if k=='key1' then dosomething()
---@function dsl.key2
elseif key=='key2' then dosomethingelse() end
end
__newindex = function(t,k,v)
---Does stuff, then calls somecallback
--@function dsl.case1
--@usage dsl.case1 = somecallback
if k=='case1' then dostuff() v(somearg)
---Does more stuff, then calls somecallback
--@function dsl.case2
--@usage dsl.case2 = somecallback
elseif k=='case2' then domorestuff() v(otherarg) end
end
})
... and the reason for this weirdness is that I *want* to think of dsl.case1 and everything else as functions rather than fields - and the reason for *that* shouldn't matter; I want the tooling to enable my way of thinking however "crazy", otherwise I'd still be doing Java . But I use Lua *precisely* because it allows me to concisely express these constructs, which might look crazy on the surface but can be extremely useful.
Having said all this, I'd be happy to just have the __call thing sorted out, because, contrary to what I previously stated, there is no way to have a *fully* functioning Codea execution environment, as ---@function [parent=#global] tween and ---@field [parent=#global] Tween#tween tween still clash, making autocompletion fail.
|
|
|
Re: How to document inherit relation [message #1279397 is a reply to message #1278771] |
Fri, 28 March 2014 13:34   |
Eclipse User |
|
|
|
hi,
Ouch complex discussion, I will try to answer but sorry if I miss the point.
To be clear, I will explain some concept.
For us:
when we talk about parent of type, we talk about type inheritance.
when we talk about parent of field, we talk about field container. (#global is a special case to define a global variable maybe not a really good idea...)
Documentation language should explain the API not the way it is implemented.
For us a type is a contract between API users and API developers. It describes the constraints on a table (or even on a function, but we will not talk about that to simplify the problem).
A Type has fields. Fields are typed but are not type. A type could have 2 fields, typed with the same type and even could reference itself. (ouch not sure this is really clear, we need a sample )
--- @type node
-- @field #node next
-- @field #node previous
In this case field and type is clearly 2 different notion. But I understand some time, this 2 notions seems so closed that you would have to manipulate it as 1 concept. We should probably find a better notation (maybe, the [parent=#blabla] is not the best one) We will think about that.
Waiting for the next release we will provide a way to declare type "callable".
The syntax will looks like something like that :
--- @type dsl
dsl = setmetatable({},{
---@callof #dsl
--@return #sometype some crazy stuff
__call = function() return crazystuff() end
__index = function(t,k)
---@function[parent=#dsl] key1
if k=='key1' then dosomething()
---@function[parent=#dsl] key2
elseif key=='key2' then dosomethingelse() end
end
__newindex = function(t,k,v)
---Does stuff, then calls somecallback
--@field[parent=#dsl] case1
--@usage dsl.case1 = somecallback
if k=='case1' then dostuff() v(somearg)
---Does more stuff, then calls somecallback
--@field[parent=#dsl]case2
--@usage dsl.case2 = somecallback
elseif k=='case2' then domorestuff() v(otherarg) end
end
})
We should release a milestone release in 1 or 2 weeks, you will be able to test it. (we have added inheritance and map/list concept)
If you have any feedback 
|
|
|
Re: How to document inherit relation [message #1280570 is a reply to message #1279397] |
Sun, 30 March 2014 11:14   |
Eclipse User |
|
|
|
Hi,
looking good! I like the @callof syntax, looking forward to the next milestone!
Thanks for your clarification and the dsl example, it helped me better understand the problem domain (and what luadocumentor expects). It is true that once LDT gets @callof, one should be able to document basically everything in one way or another. Which is great - awesome job there!
What I was trying to get across is that the "right" way to luadocument things is not what I'd "instinctively" think of. So perhaps it's better to take my rants as an RFC of sorts for an LDT 2.0 roadmap.
Let's try this. For the sake of argument, let's assume you guys do decide that [parent=#blabla] is not the best way after all. You are looking at the following snippet:
---@field [parent=#global] #tab tab
---@field [parent=#tab] #tab.subtab subtab
---@field [parent=#tab.subtab] subfield
that is meant to refer to something that exports 'tab' (along with its .subtab.subfield) to the global namespace (which isn't usually a wise thing - but this example works also if 'tab' were just a type as opposed to a field). Along with the field struct, it exposes both the implicitly created *types* "tab" and "tab.subtab" in the Outline view in Eclipse.
Again for the sake of argument, let's say that after some brainstorming, you guys decide that the above should instead look like this:
---@field tab
---@field tab.subtab
---@field tab.subtab.subfield
Moreover, you decide that this should *not* result in having 'tab.subtab' as a "root" type in the Outline. Actually, since you want to be really fancy, you don't want the type 'tab' there (in the Outline) either, because in this case it's not really a (user-facing) "type" - it's just a necessary "crutch" to allow the definition of the global *field* 'tab', which is what the API developer wants the API users to see and use. (BUT - if one were to explicitly add ---@type tab, then it *should* be in the Outline).
Very well! At this point in this hypothetical scenario you have your user story as described above. Now comes the hard part: how to actually implement it in LDT, with all the nasty complexity of internal models, metalua etc.
Ok, at this point take a couple minutes to try to answer that question: assuming that you *wanted* to have LDT behave like described above, *how* would you implement it?
So. Using this point of view, my post above would be better expressed this way:
Assuming that you guys *want* to implement that kind of behaviour (described above) in LDT, perhaps one way of getting there without too much work could be to have two kinds of "types". One is the current ---@type - explicitly declared, shows up in the outline, etc. The other would be an "implicit" type that is created behind the scenes alongside any other declaration (field, function, etc). This second "type" would just be a *container* according to the current way of modeling [parent=#blabla] relations.
In other words, this would simply mean that everything automatically becomes a potential *container* for other things. Getting back to the specific __call issue, using the tween example, you'd get this working as intended, for "free" (i.e. without coding any specific handling of __call):
---@function tween
---@field tween.foo
---@field tween.foo.bar
because in the model, tween() - the function - would automatically have a "hidden twin" container, ready to accept tween.foo in it.
(EDIT: or seen yet another way: instead of my suggestion *everything is a type* (which is confusing terminology for the reasons outlined by Simon) think of *everything is (or can be) a table*; namely, ---@fields and ---@functions are also tables, initially childless when declared, but ready to become "parents", like tween() above as soon as tween.foo comes about)
And my questions then would be: if you'd *actually* like to have this in LDT, does my idea have any merit? And if you do *not* want to have this in LDT, why not? (as I said initially, I'm sure there must be many many reasons I didn't think of).
[Updated on: Sun, 30 March 2014 12:26] by Moderator
|
|
| |
Goto Forum:
Current Time: Wed Mar 19 19:39:23 EDT 2025
Powered by FUDForum. Page generated in 0.04811 seconds
|