lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Jonathan Goble once stated:
> On Fri, Jun 16, 2017 at 3:45 PM Soni L. <fakedme@gmail.com> wrote:
> 
> > I have this Lua code:
> >
> > local string = "" print(string.format("%X", 16777216))
> >
> > And it works perfectly, but I was told it's wrong? What's wrong with it?
> > Why shouldn't I do this?
> >
> 
> Let's break it down:
> 
> > local string = ""
> 
> The variable `string` is now an empty string and, in this scope, no longer
> references the `string` standard library.
> 
> > print(string.format("%X", 16777216))
> 
> Here, Lua first looks up `string.format`. While `string` no longer refers
> to the string standard library, it is an actual string, and strings (since
> Lua 5.1) have a metatable with an __index metamethod pointing to the actual
> string library (which isn't changed by your local `string` assignment, nor
> would an assignment to the global `string` affect it). So the lookup of
> `string.format` produces, via metamethod, the string standard library
> function `format`. From there, you can call it with whatever arguments you
> want.
> 
> So why is it a bad idea? One, because indexing through a metamethod is
> slower than directly indexing the actual `string` table, and two, because
> shadowing a built-in global (whether with a global or local assignment) is
> usually a code smell (in any language) and generally shouldn't be done
> without a very good reason.

  You have to shadow the built-in globals for modules written in Lua 5.1
because the global environment goes away when you call module().  I still
do that in Lua 5.3 because I attempt to maintain compatability with Lua 5.1:

	local _VERSION     = _VERSION
	local math         = require "math"
	local string       = require "string"
	local io           = require "io"
	local pairs        = pairs
	local tostring     = tostring
	local type         = type
	local print        = print
	local pcall        = pcall
	local getmetatable = getmetatable
	
	if _VERSION == "Lua 5.1" then
	  module("org.conman.table")
	else
	  _ENV = {} -- luacheck: ignore
	end

	function dump(name,value)
	 -- ...
	end

	if _VERSION >= "Lua 5.2" then
	  return _ENV -- luacheck: ignore
	end

  Yes, I require() the base modules because that signals intent.  If I could
require() global functions like type() or pcall(), I would do that as well
(if I could do that, a side effect is that the only global in scope would be
require()).

  -spc