I have no knowledge of Lua, but I don't see what
is problem with print
here, the function print is supposed to print output to output device
in most of programming languages, just as in this case, so I don't
understand why we should want to use return (which is supposed to
return some data / pointer back to function it was called from) in
this case? I mean if we can pick if we should use print or return as
recommended way to print text, I would vote for print(), especially if
it has better performance that the implementation using return.
On Fri, Apr 13, 2012 at 1:45 PM, Tim Starling <tstarling(a)wikimedia.org>
wrote:
At the moment, in the Lua support extension we
have been developing,
wikitext is output to the wiki via the return value of a function. For
example in wikitext you would have:
{{#invoke:MyModule|myFunction}}
Then in [[Module:MyModule]]:
local p = {}
function p.myFunction()
return 'Hello, world!'
end
return p
This is all nice and elegant and will work. There is an alternative
convention commonly used in scripting languages (and programming in
general for that matter), using a print function:
local p = {}
function p.myFunction()
print('Hello, world!')
end
return p
I would have been happy to leave it as Victor Vasiliev made it, i.e.
using return values, but I happened across a performance edge case in
Lua which made me think about it. Specifically, this:
function foo(n)
s = ''
for i = 1, n do
s = s .. toString(i)
end
return s
end
has O(n^2) running time. For 100,000 iterations it takes 5 seconds on
my laptop. Apparently this is because strings are immutable, so the
accumulator needs to be copied for each concatenation. It's very
similar to the situation in Java, where a StringBuffer needs to be
used in such an algorithm.
It's easy enough to work around, but the problem is obscure enough
that I think probably most of our users will not realise they need to
work around it until it becomes severe.
It would be possible to provide a print() function which does not
suffer from this problem, i.e.
function foo(n)
for i = 1, n do
print(i)
end
end
could run in O(n log(n)) time. Intuitively, I would expect that
providing such a print function would encourage a programming style
which would avoid at least some instances of repetitive concatenation.
The performance issue is probably no big deal, since most templates
are probably not going to be concatenating hundreds of thousands of
strings, and 5 seconds is still quicker than the time it takes most of
our featured articles to render at the moment. But like I say, it got
me thinking about it.
Does anyone have any thoughts on return versus print generally? Are
there other reasons we would choose one over the other?
-- Tim Starling
I don't see a problem with supporting both. Considering that you don't
want the return value of *every *function to always be printed, just the
return value of the function directly called by #invoke, you can just
document #invoke as implicitly translating to "print( foo() )". Is there
an equivalent parser tag which does *not* print output? That would make
the parallel even clearer.
Having a print() function would be very useful for debugging; you could
turn 'debug mode' on on sandbox pages with an input arg (I assume #invoke
and friends can take arguments?) and something like
{{#invoke:MyModule|MyFunction|debug={{#ifeq:{{SUBPAGENAME}}|Sandbox|true|false}}}},
and output debugging data with more flexibility if you had a second channel
for printing.
Separately, it would be awesome to have some sort of 'intellisense' hinting
for potential pitfalls like this. I've recently been doing a lot of work
in MATLAB, and it has a really effective hinter that warns you, for
example, when you change the size of a matrix inside a loop and encourages
you to predefine it, which is a similar concept. I assume an editor with
syntax highlighting etc is somewhere on the development roadmap, albeit
probably fairly low down, so I guess add this as an even lower priority!
--HM