Wikipedia talk:Lua style guide

Latest comment: 1 year ago by Uzume in topic Naming conventions

WMF coding conventions edit

While there's nothing saying we must follow mw:Manual:Coding conventions locally, I'll summarize the differences here for those not familiar with them.

  • Indent with tabs, not spaces.
  • Spaces should always be used inside parentheses and braces, unless they are empty. For example, foo() or foo( arg ), never foo(arg).
  • No space between a function name and the opening parens/braces for the call. But do put a space between a control structure (e.g. if, function) and any paren. Although Lua doesn't require parens with control structures, so that's less of an issue than it is in JavaScript or PHP.
  • Pretty much never put multiple statements on one line.
  • Multi-line statements are indented one extra level, not hanging. There is a tendency towards the following, for clarity:
someFunction( arg1, arg2,
    "some long string or something"
)

if foo or
    bar or
    baz
then
    ...
end
  • While this page doesn't currently have anything to say about semicolons, in Lua code they're generally avoided except when necessary (i.e. a statement ending with a function call is followed by a statement starting with a parenthesized expression) or when multiple statements are on a line.
  • While this page doesn't currently mention it, spaces should also be used around all operators.

As I said, we don't have to match the WMF coding conventions if we don't want to. I'm just putting this out there for discussion. Anomie 06:15, 27 February 2013 (UTC)Reply

Doc blocks edit

Doc blocks probably shouldn't be used once 1.21wmf11 (with /doc subpages) is deployed, since an edit to update the doc block will invalidate the cache of all pages using the module. If doc blocks are used for some reason, luadoc style is probably the way to go. Anomie 06:15, 27 February 2013 (UTC)Reply

FYI: I am sure those statements were pertinent in 2013 but I believe LDoc has now taken over where LuaDoc used to be. —Uzume (talk) 11:21, 13 March 2023 (UTC)Reply

Naming conventions edit

Unless the function is going to be called both from #invoke and directly from other Lua modules, there's little point in exporting the "underscore" version of the function. In which case you don't even need the underscore:

local p = {}

local function foo( arg1, arg2 )
    -- Code goes here
end

function p.foo( frame )
    return foo( frame.args[1], frame.args[2] )
end

return p

Note also that extracting all the arguments just to pass them to another function may be counterproductive, especially if there are a very large number of them. Remember they all would need to be pushed onto the stack for the function call, after you've probably already extracted them into local variables when pulling them out of frame.args. Anomie 06:15, 27 February 2013 (UTC)Reply

It is also easy to detect if the module is being initialized as the "main" module during a direct #invoke or if it is being initialized as a library module during a require. Module initialization can detect this and return a different table specific to either, e.g.,:
local lib, main = {}, {}
main.api, lib.invoke = lib, main
local p
if select('#', ...) > 0 then -- can shorten this to just ... testing if the first arg is nil or not
    p = lib
else
    p = main
end
local function lib.foo( arg1, arg2 )
    -- Code goes here
end
function main.foo( frame )
    return lib.foo( frame.args[1], frame.args[2] )
end
return p
It should be noted that all Scribunto modules are effectively initialized during a (larger) #invoke so there will always be a frame, even when loaded as an API library via require. I never understood the need for the leading underscore functions. Other options are to use ... and compare if there is only a single argument that is equal to mw.getCurrentFrame() and act accordingly. —Uzume (talk) 11:56, 13 March 2023 (UTC)Reply

Spaces after parens, braces, and curlies edit

personally i do not like them, but it seems to be all the rage now, and it's definitely the style mw seems to force for JS, and i guess Lua too. so, unless someone says differently, we should add to the style guide:

-- do this:
function Foo( param1, param2 )
    local x = { a = "this", b = "that" }
    local y = Bar( 1, 2, 3 )

    x[ 6 ] = 11;
end


-- and not
function Foo(param1, param2)
    local x = {a = "this", b = "that"}
    local y = Bar(1, 2, 3)

    x[6] = 11;
end

peace - קיפודנחש (aka kipod) (talk) 16:56, 27 February 2013 (UTC)Reply

x[ 6 ] seems to be seldom used in the MediaWiki codebase, x[6] is more common. Spaces are more likely with a complex expression than "6"; in JavaScript code, you also need to differentiate between brackets used for indexing and brackets used for array literals, regular expressions, and CSS selector strings. Anomie 14:55, 28 February 2013 (UTC)Reply

Module naming edit

Another thing that needs agreement is module naming convention. here is my $.02:

  • Module names will not contain spaces.
  • Module names should not contain colons, or any other punctuation
  • Module names should indicate what the module does, rather than where it is used

If anyone disagrees with the "no spaces" rule, please discuss. If anyone think punctuation marks (e.g., "/" "," "." ";" ":", single and double quotes etc.) should be allowed, i suggest we specify specifically which are the "kosher" ones, and ban all the rest, so please advocate here which punctuation should be exempt from the rule.

peace - קיפודנחש (aka kipod) (talk) 16:56, 27 February 2013 (UTC)Reply

One possibility I've considered for modules that are really specific to a single template is to name them like "Module:Template:Example". I also see a few other people have shared my thought with respect to naming user-specific sandboxes, naming them as "Module:User:...". Anomie 15:01, 28 February 2013 (UTC)Reply

CodeEditor switched to tabs edit

So CodeEditor has switched to tabs, and it looks like the advice here to use four spaces is now outdated. It doesn't look like this is going to be changed to accommodate the existing modules written with four spaces - see bugzilla:39616 and bugzilla:54141. Should we update this guide to specify using tabs? — Mr. Stradivarius ♪ talk ♪ 01:13, 29 October 2013 (UTC)Reply

 Y One problem with tabs is how wikipedia renders them. While in a notepad 1 tab = 4 spaces. On wikipedia it does not 1 tab is larger then 4 spaces. This becomes a problem when you have 6 tabs or 24 spaces, what could be small on a notepad gets exploded on wikipedia. While yes I do use tabs outside wiki spaces are prefered on wiki,  B unless the css for lua code is changed kind of like how a .css pages on wiki are treated with a line number and proper tabing, I would say spacing is prefered.. Cky2250 (talk) 01:27, 29 October 2013 (UTC)Reply
Unfortunately code on a Module: page within a <pre> element is typically rendered with tabs having a width of 8, which eats up horizontal space quickly. (For some browsers, the tab-size CSS property (or vendor-specific equivalents) can be used to specify another width.) Agreed that the coding style recommendation ought to match what the embedded editor is doing. isaacl (talk) 01:37, 29 October 2013 (UTC)Reply

Groan, what a mess. I know Module:Convert/data is stupidly big, but here are some extracts of how it appears when viewing the module page:

local all_units = {
    ["cm/s2"] = {
        name1    = "centimetre per second squared",
        name2    = "centimetres per second squared",
        symbol   = "cm/s<sup>2</sup>",
    },
    ["ft/s2"] = {
        name1    = "foot per second squared",
        name2    = "feet per second squared",
        symbol   = "ft/s<sup>2</sup>",
    },

When viewing the page in the CodeEditor (with scripting on, after clicking edit), the same stuff looks like this (because it has a single tab to indent the lines like "name1"):

local all_units = {
    ["cm/s2"] = {
    name1    = "centimetre per second squared",
    name2    = "centimetres per second squared",
    symbol   = "cm/s<sup>2</sup>",
    },
    ["ft/s2"] = {
    name1    = "foot per second squared",
    name2    = "feet per second squared",
    symbol   = "ft/s<sup>2</sup>",
    },

If all the indents were "corrected" to use 4-column tabs, this is how the module page would appear (when not editing):

local all_units = {
        ["cm/s2"] = {
                name1    = "centimetre per second squared",
                name2    = "centimetres per second squared",
                symbol   = "cm/s<sup>2</sup>",
        },
        ["ft/s2"] = {
                name1    = "foot per second squared",
                name2    = "feet per second squared",
                symbol   = "ft/s<sup>2</sup>",
        },

I used a tab because the module is so large that tabs make a useful reduction in size. I don't mind whatever outcome is decided, but frankly "spaces everywhere" is the only thing that is manageable by editors who aren't used to this kind of nightmare. However, I see that our opinion on what the CodeEditor does is irrelevant. I just converted a small module to use 4-column tabs, and Module:Convert/show now looks silly when viewing, but is ok when editing. Johnuniq (talk) 04:36, 29 October 2013 (UTC)Reply

We might be able to change the behaviour of GeSHi to use smaller tabs if we ask nicely in bugzilla, so it's not necessarily the case that we are stuck with 8-column tabs when viewing modules. Also, bugzilla:54141 might not be the final word on this - if there is interest here, we could try reopening it. My personal opinion is that tabs are actually better than spaces for writing code, as long as they are used consistently, which of course is the problem here. (It would be a shame to lose the Monty Python reference in the style guide if we do decide to switch to tabs, though.) — Mr. Stradivarius ♪ talk ♪ 05:00, 29 October 2013 (UTC)Reply
I suppose we shouldn't worry about it—accept that the CodeEditor now forces us to change the style to use 4-column tabs, and ask to have GeSHi changed to match (I wonder if it can do that only for Lua). I know that MediaWiki is strictly indent-using-tabs because that saves significant amounts of memory, and is the most flexible for personal preference in a programmer's editor. Anyone who is used to this sort of thing can handle it, and those who are not used to it will get confused if they ever work in a local text editor with copy/paste, but no significant harm will be done as the whitespace does not matter. We could write a module to fix all indents—for input, it would be told the name of the module and "4" (new style) or "8" (old style) for the widths of any existing tabs, and it would put the entabbed result in a pre block in a sandbox, to be pasted into the module. Or, we could let people deal with it as they see fit—I would not recommend enforcing a style by editing modules for style because that's sure to irritate someone and serves no real purpose. Let me know if you want me to write Module:Entab, although I suppose a more generic name like Module:Style would be better in case it ever did anything else. Any better idea for a name? Johnuniq (talk) 06:10, 29 October 2013 (UTC)Reply
Probably a JavaScript gadget would be better than a module, as it can be run directly from the edit window. With a module, you would have to go through the hassle of substing it, and then looking at the diff to see if it worked properly or not. With a user script, you would know that it worked straight away. Also, I was under the impression that the "4" and "8" tabs are actually the same character, and the width of the character is decided by the software that you're using. I've never really read around the subject, though, so I couldn't say for sure. — Mr. Stradivarius ♪ talk ♪ 06:52, 29 October 2013 (UTC)Reply
Yes, there is only one kind of tab character, and depending on how an editor is configured, the tab will expand to make 8-character columns (the "standard"), or 4-character columns in the case of the changed CodeEditor, or whatever the configuration on the software used to display the text says. I mentioned the 8/4 input because current Lua source that happens to have tabs (because it was prepared somewhere else and was pasted into the edit window) should be using 8-column tabs (an example being Module:Convert/data), while someone writing a new module in the new CodeEditor will get 4-character column tabs if they press the Tab key. A quick test suggests that the CodeEditor does not convert indents consisting of a string of spaces to tabs, so scripts will end up with weird mixtures. A tool to clean up should re-indent everything assuming 4-character column tabs as the default, but with an option to convert 8-character columns for old code. You are correct that some Javascript gadget would be better, although ideal would be a button on the Advanced toolbar of the CodeEditor. Johnuniq (talk) 09:33, 29 October 2013 (UTC)Reply
Hi, +1 for having GeSHi configurable (to 4-column tabs for example). Instead I don't understand very well bugzilla:54141: the behaviour of CodeEditor is correct for me, it doesn't replace existing spaces with tabs as expected ("replacing spaces with tabs" should be considered as a specific feature of a text editor, that CodeEditor doesn't yet have) --Rotpunkt (talk) 10:00, 29 October 2013 (UTC)Reply
I might not have explained myself very well in bug 54141. I didn't mean that CodeEditor was replacing spaces with tabs - it wasn't. The problem is that in modules with a mixture of tabs and spaces, editors will write their code in CodeEditor with 4-column tabs, and they will expect their code to be indented in the same way that they see in CodeEditor. Then when they save the page, they will see the same code in GeSHi with 8-column tabs, and it will look strange. Suddenly code will seem to be indented where it wasn't before, or it may not be indented enough. — Mr. Stradivarius ♪ talk ♪ 10:21, 29 October 2013 (UTC)Reply
Sure, so we should update GeSHi to use the same columns of CodeEditor (anyway it would be nice if CodeEditor had a button "Retab" for fixing spaces=>tab in the entire document). BTW do you have already tried to change the tabsize of CodeEditor? I have read here that it could be configured via javascript (setTabSize of Ace I guess). Or is there a shortcut? --Rotpunkt (talk) 10:46, 29 October 2013 (UTC)Reply
No, I've never tried to change any CodeEditor settings. I don't know JavaScript, which isn't a good start. :) — Mr. Stradivarius ♪ talk ♪ 11:31, 29 October 2013 (UTC)Reply
Re the comments above about updating GeSHi, I'm not sure it's the way to go. GeSHi just outputs the tabs, and we can as easily include the necessary CSS in MediaWiki:Common.css or in Scribunto. The problem is that the needed CSS tab-size isn't available yet in all browsers. Try it below:
0123456789ABCDEF
	↑ tab goes to here in your browser
It should indicate "4" in modern versions of Firefox and Chrome, Opera 17.0 (and maybe earlier, certainly earlier if we add -o-tab-size), and Safari 7.0+. But people with IE, older Safari, Android browser, and maybe others will probably be stuck at "8". Anomie 11:40, 29 October 2013 (UTC)Reply
Do you think it's ok with this configuration: common.js, common.css ? I have used "4" but it's configurable with any value. So we can sync the CodeEditor tab-size with the view when page is saved. --Rotpunkt (talk) 14:09, 29 October 2013 (UTC)Reply
Isn't the JS bit already the default? Anomie 16:15, 29 October 2013 (UTC)Reply
Oh thanks, but if I remove ".source-lua" it seems not to work for lua syntax. --Rotpunkt (talk) 16:46, 29 October 2013 (UTC)Reply
I didn't know about this discussion until Mr. Stradivarius pointed me to it, but I'm proposing basically the same thing at Wikipedia:Village pump (technical)/Archive 120#GeSHi tab size. I'd appreciate if you all weighed in. – Minh Nguyễn (talk, contribs) 10:25, 25 November 2013 (UTC)Reply