The Good Stuff of Day 2, Lua Metatables

The “Seven Languages” books (and probably all of the “Seven in Seven Weeks” series) is more a collection of amuse bouche (amuse bouches? amuses bouche? amusi bouchi? nahh) than of entrees or even appetizers. And that makes sense because there’s no way to fit all the details on seven languages in one book. But it also means you read a section and find yourself going “What the heck was that? It was really tasty, but I really want more.”

So it was when I read the section on metatables. Sure there is some info on metatables in Seven More Languages but I really wanted more. I found the Lua book at http://www.lua.org/pil/13.html to be very useful in augmenting it. All of chapter 13 is devoted to metatables and metamethods. I also figured out why the object-oriented stuff got put in Day 2.

So, metatables!

The Amuse Bouche

All tables have metatables, but by default the metatables are empty. You can get to a metatable for a table using getmetatable(sometable) . And, hopefully not surprisingly, you can change a metatable for a table using setmetatable(table, new_metatable) .

So, how do you create a new metatable? And what can go there?

Recall the Florida info table:

stateFL = {
    capital = 'Tallahassee',
    bird = 'mockingbird',
    population = 19890000
}

Trying to print it just gives its address, as is done in many languages.

> print(stateFL)
table: 0050D708

But you can create a function to convert the table to a proper string:

function to_string(t)
    local result = {}
    for k, v in pairs(t) do
        result[#result + 1] = k .. ": " .. v
    end
    return table.concat(result, "\n")
end

Of course, you could just print the table using this new function print(to_string(stateFL)) but that’s not noteworthy. Instead, assign the __tostring function of the metatable. One way to do this is to create a metatable with the function as its only member and make it the metatable of stateFL

mt = {
   __tostring = to_string
}

setmetatable(stateFL, mt)

Then printing the table does the expected thing:

> print(stateFL)
bird: mockingbird
capital: Tallahassee
population: 19890000

There are lots of operators which can be overriden using metatables, including +, -, /, *, <, <=, and ==. You can also override the action when reading and writing to the table to provide different default values, tracking of all changes to the table, and read only tables.

Even though Lua has a mechanism for object oriented programming, you can use metatables to quickly create classes. The Lua book on-line shows how to create a Set class with just metatables. I’ve got a copy in the file Set.lua on my Github account.

The Set class is pretty cool and it points out another feature of Lua, that it’s a prototype rather than object oriented language. Since the first book covered Io, another prototype language, that’s not a new idea for me, but I’ll still finish up day 2 with finding out how Lua handles prototyping.

Leave a Comment

Day 2 begins: Lua Tables

A quick improvement. I complained about the code necessary to load a file into the REPL. The assert(loadfile('file.lua'))() seemed a bit long. There is a better way:

dofile('file.lua')

That’s more like it!

In writing this, I’ve come across numerous places where I’d like to add even more examples that I’ve created to try things out. If you ever want to try something for yourself, you don’t need to go to the trouble to install Lua (or, since you’re better than I am, build it for yourself). There’s an on-line interpreter with some demos at http://www.lua.org/cgi-bin/demo .

So, do you find that having one data structure that is indexed by integers and another that’s indexed by field names confusing? Would you prefer to be able to do:

a[3] = 4
a.name = 'Numbers'

Yep, Lua lets you! This is the table data structure that makes Lua worth learning.  Or so says Tate.

Table Basics

So, you can use tables for named fields as in:

stateFL = {
   capital = 'Tallahassee',
   bird = 'mockingbird',
   population = 19890000
}
stateFL.nickname = 'Sunshine State'

A quick function to step through all the entries is:

function print_table(t)
    for k, v in pairs(t) do
        print (k .. ": " .. v)
    end
end

And when printed you get:

population: 19890000
bird: mockingbird
capital: Tallahassee
nickname: Sunshine State

Okay, that looks like a dictionary like thing in many scripting languages. But then the fun begins.

You can also create an array with similar syntax:

citiesFL = {
   'Gainesville',
   'Jacksonville',
   'Miami',
   'Tampa'
}

citiesFL[5] = 'North Palm Beach'

And as output, get:

1: Gainesville
2: Jacksonville
3: Miami
4: Tampa
5: North Palm Beach

There is something a little surprising to those of us who have been in CS for way too long. The list begins at position 1, not position 0. Remember when we used to start counting with 1? Yeah, me neither.

Things get to be fun when you combine these, as in (using the previous state table):

stateFL[1] = 'Gainesville'
stateFL[2] = 'Jacksonville'
stateFL[3] = 'Miami'
stateFL[4] = 'Tampa'
stateFL[53] = 'Newberry'

Of course, there’s no need to have the numbers in consecutive order. You could even get crazy and add:

stateFL[-12] = 'Key West'

and if you really need to have an element at position 0, sure, go ahead:

stateFL[0] = 'Alachua'

It’s not like the data is stored in separate areas. In fact, the numbered data is mixed with the named data:

1: Gainesville
2: Jacksonville
3: Miami
4: Tampa
population: 19890000
-12: Key West
0: Alachua
53: Newberry
bird: mockingbird
capital: Tallahassee
nickname: Sunshine State

If you’re thinking “Well, no big deal, the number is just converted to a string,” nope. Florida is getting full, so let’s move north a bit:

citiesGA = {}
citiesGA[1] = 'Macon'
citiesGA[4] = 'Savannah'
citiesGA['1'] = 'Atlanta'
citiesGA['01'] = 'Richmond Hill

Printing this gives:

1: Macon
1: Atlanta
4: Savannah
01: Richmond Hill

A little more fun with the basics. You can access the named fields using the array notation as well, as in citiesFL["capital"] . And, just as with traditional arrays and dictionaries, this doesn’t need to be a string, so

item = 'capital'
print (citiesFL[item])

works just fine. And you do know that citiesFL.item is something completely different, right?

Still, this is not worth a whole new language. Not yet. Lua tables allow you to customize how the table works. Want to create a sparse matrix and have a different value returned? That’s where metatables come into play, but this is long enough for now, so that’ll have to wait until tomorrow.

Leave a Comment

More of Lua, Day 1: Tail Recursion Optimization

So, Lua optimizes tail recursion calls.

At first glance, this is no big deal. Very few recursive functions are tail recursive, that is, have the recursive call as the very last thing in the function, at first glance.

Consider the recursive factorial, for a real easy example.

function fact_1(num)
   if num <= 1 then
      return 1
   else
      return num * fact_1 (num - 1)
   end
end

While it looks like the recursive call is the last thing in the function, it really isn’t. The multiplication of num and the result of the result of the recursive call is the last thing done in the function, so this isn’t tail recursion.

But it can be “easily” turned into a function that is tail recursive. I quote “easily” since the first two or three or ten times you see the “easy” translation, you may not believe it, or at least may not believe it’s really easier. (I had students who figured it out the first time and others who took a lot more tries.  A lot more.)

What you have to do is carry the result with you down into the recursion. You’ll update the solution as you go, so that when you finally get to the base case, you’ll have the result ready to return. As the last step of the function. Thus, tail recursion. Code to do this is:

function fact_2 (num, result)
   if num <= 1 then
      return result
   else
      return fact_2 (num - 1, result * num)
   end
end

The only thing left to do is to rewrite the main factorial function to use this tail recursive version:

function factorial (num)
   return fact_2(num, 1)
end

Does it really matter? Does Lua really optimize tail recursion?

I tried the following non-tail recursive code and could compute up to 19,997 before getting a stack overflow error.

function sum_badly(max)
   if max <= 1 then
      return max
   end
   local other_sum = sum_badly(max - 1)
   return other_sum + max
end

And sure enough, the tail recursive version below allowed me to go to at least 100,000,000, so I’m convinced Lua does optimize tail recursion.

function sum_well_helper(max, current)
   if max < 1 then
      return current
   else
      return sum_well_helper(max -1, current + max)
   end
end

function sum_well(max)
   return sum_well_helper(max, 0)
end

The code is in my GitHub account if you want to see for yourself. The solutions to the Day 1 problems are also there.

That’s enough of Day 1 for now. Onto to tables.

Leave a Comment

Lua Function Basics

So, sorry profs who might use this book as a text. I’m going to post my solutions to the book’s problems here and/or on GitHub. (Of course, that might just be an empty set, now that I’m no longer teaching, so I’m probably not bothering many people. It’s a pity; this is an excellent book for students to work through.)

First, so I don’t have to look it up again…one of the things I asked students to do in their “Get Acquainted” assignments for each language was to figure out how to enter code in a file and then use it in the REPL. Since I’m doing functions now and it’s a pain to retype functions each time I change them, now is the time to figure that out. And Lua continues to be different from other languages. To read the file samples.lua into the REPL, use the line:

assert(loadfile('sample.lua'))()

Okay. Good thing the REPL lets me arrow up to repeat commands. That’s a bunch of typing (more than any of the Seven Languages, I think).

Function Basics

Function syntax is unsurprising and makes me happy once again I know Pascal. The first exercise asks us to write a function that will return whether or not the last digit of a number (when expressed in base 10) is 3. If I take negative values into account, a solution looks like:

function ends_in_3(num)
   return math.abs(num) % 10 == 3
end

You can return two values (or more) as shown in the function that computes the roots of ax^2 + bx + c:

function get_roots (a, b, c)
	if b^2 - 4 * a * c < 0 then
		return
	elseif b^2 - 4 * a * c > 0 then
		local root1 = (-b + math.sqrt(b^2 - 4 * a * c)) / (2 * a)
		local root2 = (-b - math.sqrt(b^2 - 4 * a * c)) / (2 * a)
		return root1, root2
	else
		return (-b + math.sqrt(b^2 - 4 * a * c)) / (2 * a)
	end
end

Along with showing how to return 0, 1, or 2 values, the code above illustrates how to create local variables. By default, variables “declared” in functions in Lua are global. If you don’t want to type this all in yourself, take a look at the function set_some_stuff in my GitHub account.

Closures

Since functions are first class items, they can be returned by other functions. So you can build a function to multiply by a given value with:

function build_multiplier(factor)
	f = function (val)
		return val * factor
	end
	return f
end

Then create a couple of functions that do multiplication:

times_3 = build_multiplier (3)
times_8 = build_multiplier (8)

And, sure enough, that non-local variable factor in the function that’s built gets assigned the correct thing, each time. So

print ("4 times 3 is "..times_3(4))

prints

4 times 3 is 12

and

print ("4 times 8 is "..times_8(4))

prints

4 times 8 is 32

Finishing Day 1

There’s a bit more in the book about functions at this point, including how you can “fake” named parameter passing and have variable number of parameters. Both of these take tables, which is the big area of focus for Day 2, so I’ll skip them for now.

I’ve got a big example working that convinces me that there really is optimization of tail recursion in Lua. Convincing anyone else will take a bit more space than I’m willing to use now, so, like the author, I’ll make it a side bar and give it its own post. (If you’re really anxious, it’s in my GitHub repo now.)

For my final words on Day 1, let me quote Bruce Tate, the author, since he did a pretty good job of reading my mind at this point:

At this point, you’re probably thinking Lua is an easy-to-use scripting language, but with nothing particular to make it stand out in a crowd. That was certainly my first reaction when I encountered the language.

Yep. I definitely agree with this. Let’s hope I can agree with his next line as well:

Then I ran into Lua’s killer feature that makes its expressiveness possible: tables.

Leave a Comment

Lua: Day 1

The Call to Adventure

So, it’s good I played a little with Lua as I was installing it, because the first day’s material is just not that inspiring. The big problem presented is that CSV files have some problems. Specifically, there’s no way in CSV to indicate constraints or collections. Okay, fine. That’s not really what CSV is all about. But apparently this should be enough to motivate me to keep going. Meh. It’s good I was motivated to begin with. (Like, what about XML?)

The description of Lua as a table-based language that can easily adjust to different paradigms holds lots of promise. That one of these paradigms can be the prototype paradigm is even more interesting. In Seven Languages, the only prototype language was Io and it’s fallen from popularity. When I last taught it, students poked around and realized there had been no activity on the Io community for months. (JavaScript is also a prototype language, but there’s a lot of other baggage with JavaScript.) The book doesn’t get to tables until the second day though, so enough said, for now.

From the first day, the most I can say is that Lua is a fairly typical scripting language so far. The REPL (Read-Eval-Print Loop) is a bit unusual in that you can’t just type:

2015

and get the result

2015

Instead, you need to explicitly indicate you want Lua to evaluate an expression, as in:

=2015

or you need to indicate you want that value to be returned, as in:

return 2015

I’ve also been doing a lot of Python recently, so the fact that Lua is not at all line-based is a nice change. You want to enter two commands over three lines like:

print
"Hello" print
" world"

Yeah, sure, go for it.

Lua is implemented using a “strict subset of ANSI C” (umm, quotes, yeah, they come from “Seven More Languages in Seven Weeks” unless otherwise indicated). It just uses floating point for all numbers, but does allow for the % operator. And it does something sorta reasonable when you use % and floating point numbers. 13.2 % 4 is 1.2 and 14 % 3.3 is 0.8 . (Let’s not think about negative numbers now, okay?)

There’s also exponentiation and it uses the correct precedence: 2 ^ 3 ^ 2 is 512, not 64. Expressions are otherwise unremarkable.

Booleans have the literals true and false and use real words instead of symbols (and, or, not). As I fussed about before, not equals is ~= . Only numbers and strings can be compared (and strings can only be compared to strings, numbers to numbers, not of this 42 < “43” stuff.) Strings can use single or double quotes. Use # before a string (or variable containing a string) to get its length. Use .. for concatenation. (And no, you can’t get the length of a number; I tried.)

Lua’s quite laid back about uninitialized variables and parameters. Try to print a variable that has no value and you get nil. Of course, it’s pickier if you try to use uninitialized variables in expressions. Combining this with multiple assignment leads to some interesting results:

x, y, z = 1, 2, 3

behaves as expected (if you expect x to get 1, y to get 2, and z to get 3). And

x, y, z = 1, 2

doesn’t complain, just sets z to nil (even if it had a value before). Finally,

x, y, z = 1, 2, 3, 4

just ignores that pesky extra 4 at the end.

Control structures are also fairly routine. They’re ended with end, so there’s no problem with dangling elses. The for loop makes the Pascal programmer in me happy:

for i = 1, 5 do
   print("i = " ..i)
end

And the loop control variable behaves nicely–it is reset to the “correct” value at the beginning of each loop. You can change it, but it gets changed back:

for i = 1, 5 do
   print("Before increment, i = " ..i)
   i = i + 1
   print("After increment, i = " ..i)
end

results in:

Before increment, i = 1
After increment, i = 2
Before increment, i = 2
After increment, i = 3
Before increment, i = 3
After increment, i = 4
Before increment, i = 4
After increment, i = 5
Before increment, i = 5
After increment, i = 6

Yay!

And i is nil after the loop. (Since I want to practice more with GitHub, I’ll be putting programs in the repository https://github.com/Annie29/7MoreLanguages . This is the first one out there.)

There’s also while and repeat loops (yes, repeat, like Wirth and God intended it, none of this do silliness!).

The author tosses off what I think is an important feature: Lua optimizes tail recursion. Now, tail recursion optimization was covered in detail in Seven Languages in Prolog, Clojure, Erlang, and Haskell, so maybe it’s just not that exciting. Maybe I’m prejudiced since I remember how hard it was for students to understand the benefits of tail recursion removal. But since I want to play with functions more before going on, especially since they’re first-class values and I’ve only recently grokked closure, and this has gotten long enough, so let’s hold that off until the next posting.

Leave a Comment

Installing Lua

Before ever starting, y’all can hate me because I installed Lua for Windows. From a binary. Yes, I should build it for myself. And my computer does dual boot into Linux. Well, tough. That’s not what we’re here to do today. (Maybe when there’s “Seven Operating Systems in Seven Weeks?”)

(For those who don’t automatically think a binary build of Lua for Windows is a bad idea, you can find it at https://github.com/rjpcomputing/luaforwindows/releases .)

One nice thing about Lua for Windows is it comes with a really quick “tutorial.” Okay, it’s more like a bunch of examples, but it’s a fast way to see what Lua looks like.

Anyway, there are (at least) three syntax things that drive me crazy about programming languages:

  • how to mark comments
  • how to indicate “not equal”
  • how to handle else if

So far, Lua does not disappoint. It does have single line double hyphen comments. Good, fine, I’ve seen those before in Ada. But ah, the multiline comment is a thing of Lua beauty.

--[[
Here's that multiline comment,
folks! ]]

Yeah. Hyphen, hyphen, square bracket, square bracket. Ended of course with two close square brackets. And no hyphens.

And the not equal is almost as much fun.

a ~= b

Tilde! And it doesn’t mean match. Dammit.

It makes the else if, elseif, downright disappointing.

But if I’d wanted more of the C/C++/Java/C# family, I wouldn’t be working through this book!


Along with the Seven More Languages book, the first edition of Programming in Lua is available on line (at http://www.lua.org/pil/contents.html), so I figured I’d read that as well. There’s a sample factorial program in the first chapter:

-- defines a factorial function
function fact (n)
   if n == 0 then
      return 1
   else
      return n * fact(n-1)
   end
end

print("enter a number:")
a = io.read("*number") -- read a number
print(fact(a))

I figured I’d try it out, so I entered it (okay, cut and pasted it) and ran it from the iExecutor that comes with the Windows version of Lua. And it failed. Damn, had the language changed so much since the first edition that this program no longer worked?

Poking around a bit, I realized that the problem was that the input line was not working. My first impulse was there had to be a typo. a = io.read("*number") ? Really? Surely the quotes didn’t belong there; it should be more C scanf-ish line: io.read(*number) and then we’ll use number in the next line.

Wrongo. The input line is in fact correct (and I realized again that Lua is going to be fun). The problem was iExecutor. While it did run code with no input just fine, there seem to be problems in reading input. As soon as I ran the program from the command line, it was just fine. Fortunately, Notepad++ does recognize Lua and it’s easy to run programs edited in Notepad++, so all is well.

I guess I should read more about iExecutor. But Lua seems like more fun for now.

Leave a Comment

Seven Languages, More or Less (Okay, More)

or Laurie Lists Lotsa Languages Like Lua

So, when faced with a book like “Seven More Languages,” an obvious first question is “What are the seven more languages?” I was dismayed or delighted to realize I had no idea what any of them were:

  • Lua
  • Factor
  • Elm
  • Elixir
  • Julia
  • miniKanren
  • Idris

This promises to be a fun adventure.

Of course, knowing a little about a language doesn’t take all of the adventure out of it. The first “Seven Languages” used the languages:

  • Ruby
  • Io
  • Prolog
  • Scala
  • Erlang
  • Clojure
  • Haskell

At least there I had taught both Lisp (aka Clojure) and Prolog in AI classes, had taught lots of Java, so some of Scala wasn’t foreign, and had played with Ruby and Rails. Yeah, Io was, and remains, highly esoteric, but I’d heard of Haskell and Erlang and knew they’d be worth playing with. There is plenty of adventure to be had in these languages and the More Languages promises even more adventure.

There’s something in me that likes lists (Lisp and I are about the same age). So, I figured I’d pause before jumping into to Lua to make a couple more lists. Let’s start with the languages I learned first, as embarrassing as that may be since it starts with BASIC (and none of that Visual stuff either).

  • BASIC, FORTRAN, and COBOL as an undergraduate
  • Pascal in night school while in the Army (as a purely theoretical exercise, since the instructor never figured out the compiler for the TRS 80)
  • IBM 380 Assembly, Lisp, Ada, and Modula-2 in grad school

Then I started teaching and added:

  • C++
  • 68000 Assembly
  • Java
  • Visual Basic
  • C#
  • Perl
  • Python
  • Tcl/Tk

Presenting in GDG meetings added

  • Go
  • Dart
  • JavaScript and HTML

Working with K12 programs included

  • Greenfoot
  • Jeroo (a personal favorite)
  • Scratch and Squeak (and BYOB, Snap, and Blockly)
  • Alice
  • Karel
  • Lightbot
  • Robocode
  • Pivot
  • Processing

I did a little Smalltalk with the programming contest one year and some R as part of exploring big data. Should I count things like Bash, Awk, SQL, etc.? Nope, I don’t think so.

Yes, C is missing. I can probably fake my way through C, but I decided it was too ugly to learn in my grad school programming language survey class. There were a bunch of us who each had a language and during a typical class, we’d hear from the C guy, the COBOL guy, the Pascal guy, the PL/I professor and the Ada gal. That was enough C for me. (But after teaching “C++” for engineering freshmen, I’d be hard pressed to tell you why I wasn’t teaching C.) I had a friend who majored in comparative lit in college and he decided to never read Hamlet. I’ve used him as inspiration any time I’ve thought I should know more C.

Instead, I should learn Lua, I do believe.

Leave a Comment

Older Posts »
Follow

Get every new post delivered to your Inbox.