Author Archives: Leah Hanson

Well, that was embarrassing.

I have long been confused by the strange behavior of integers as arguments to functions.
If I pass a variable into a function, I expect the function to be able to modify it.
This expectation applies to variables local to the calling context and to global variables;
it also applied to Strings and Floats and Integers and Chars.
When I’m trying to do something
(like modifying Int arguments inside a function and seeing the change outside it)
and it isn’t working, I fiddle with it until it does.

However, today, I decided that I should actually ask why it didn’t work the way I expect.
Today, I had the embarrassing experience of correcting my fundamentally flawed model of how variables work.
I’m going to skip over explaining the details of my previous model, since I don’t want to encourage its remaining grip on my mind.
Instead, I’m going to work through a very physical metaphor for my new understanding.

The Metaphor: A Table of Boxes and Forms and Colorful Stickers

There are two kinds of values: mutable and immutable.
Immutable values cannot be edited; they are like paper forms filled out in indelible ink.
Numbers (Ints,Floats,BigInts,BigFloats,etc), Chars, Strings, and user-defined immutable types are all immutable.
Mutable values can be edited; they are like boxes with boxes and paper forms inside.
I like to picture them as those organizer-boxes, with dividers it them.
Dictionaries, Arrays, and all other user-defined types are mutable.

There is a table (as in, a piece of furniture) of these boxes and forms; this is all the memory your program is using.
(this metaphor, as you may have noticed, is ignoring the stack/heap distinction and other implementation concerns.
I’m focused on getting correct expectations for what the value of my variables might be after I use them as arguments to a function.)
As your program executes, it fills out new forms, puts new boxes on the table, and throws out boxes and forms that it’s not using.
It also moves things into or out of the boxes.

There is one other component to this setup: stickers.
Any time that code is executing, it is executing within a context.
This context is made of bindings of names (variable names) to the values on the table.
We’ll model these bindings as stickers.
The name of the variable is printed on the sticker,
and the sticker is stuck to the value that the variable is currently bound to.
Each context has its own color of sticker, and ignores stickers that aren’t of its color.

Example 1: x = x + 1

Let’s say we have the variable name x bound to an Int value, 5.
This value is immutable, so it will be a paper form with 5 written on it in ink.
Because we’re calling this form by the name x, there is a sticker on the form with the name x printed on it.
Now that I’ve explained the context, let’s run the line of code x = x + 1.
First, we’ll take a look at the value on the form labeled x; it’s 5.
Then, we’ll write the result of 5 + 1 on a new form.
Finally, we’ll move the x sticker from the form with 5 written on it to the form with 6 written on it.

Example 2: a[2] = 6

Forget about x. a is a 1-dimensional Array.
Picture a as a long, thin box with three dividers in it.
Each space between the dividers is an element of a, so a is of length 4.
There is a sticker with a printed on it on the outside of the box.
Each of the spaces in the box has a paper form with a number written on it;
what numbers are written on them is not relevant to this example.

Now, let’s simulate running a[2] = 6.
(We’re simulating Julia code, so we’re indexing from 1.)
First, we’ll get a paper form and write 6 on it in pen.
Then, we’ll replace the paper in the second box from the left of a with the new form.
That’s all we need to do; notice that no stickers have been moved.

Example 3: foo(x)

Say we have our integer variable x again.
It’s a form with 6 written on it, with an x sticker stuck to it.
The sticker is blue.

Now, we have a function:

 :::.jl
 function foo(z::Int)
   z = z + 1
 end

I’m going to ignore irrelevant portions of calling this function,
including that it will return the value of z + 1.

When we run the line foo(x), we will move into the context of foo.
Our previous context is the calling context (the one calling foo).
Our current context is inside foo, so now there is a green z sticker on our form.
Now, inside foo, we’ll write 7 on a new form, and move our green z sticker to it.
Then we return from the function call, and remove all the green stickers.

What is the value of x now?

Well, the blue x sticker is still stuck to the form with 6 written on it.
This means that foo did not modify x.
In fact, passing an Int variable as an argument to a function will never modify that variable.
Inside the context of foo, we can’t see the blue x sticker at all — and we definitely can’t move it.[1]
The form is immutable, so you can’t erase and you can’t write anything new on it.
There’s nothing that foo could possibly do to change the value of x in the calling context.

Example 4: foo(a[2])

Picture the box for a again. It’s got 4 pieces of paper in it; the second one says 6.
There are no labels on any of the four forms; there is a blue a label on the outside of the box.

Now, we’ll execute foo(a[2]), where foo is the same function from the previous example.
As we move from the calling context into the foo context,
we’ll stick a green z sticker on the form in the second compartment of the box with the blue a sticker.
Now, we’ll get out a new form, write 7 on it, and move the green z sticker to this new form.
Finally, we’ll remove all the green stickers as we return to the calling context.

The value of a is unchanged.

Example 5: bar(a)

So far, we haven’t managed to mutate any arguments to a function.
This is about to change.

Picture the box for a. Let’s say that the four forms in have,
respectively, the following numbers written on them: 1,6,8,19.
None of the forms have any labels on them; the only label is the blue a on the box.

We’ll need a new function for this:

 :::.jl
 function bar(xs::Array)
   xs[2] = 42
 end

Now, let’s simulate: bar(a).
We’ll move from the blue calling context to the green callee context;
we’ll put a green xs sticker on the box.
Then we’ll take the piece of paper in the second compartment (with 6 written on it)
and replace it with a new form with 42 written on it.
Now, we’ll return to the calling context, removing the green xs sticker.
Notice that we did not move any stickers.

What is the value of a now?

It’s [1,42,8,19]. The assignment in bar did affect the value of a.
It did not affect the binding of a (the blue sticker),
but it affected which values were inside the mutable box that is the value of a.

Conclusion

I already had a sort of messy awareness of this whole thing.
I mean, I’ve brushed up against “by value” vs “by reference”;
I’m fine with writing C and using pointer;
I was good on the difference between variables shadowing and modifying a mutable box in OCaml.
But it wasn’t until today that this all clicked into place in my mental model
of how passing variables as arguments to functions works in “normal” languages, like Julia and Java and such.
Suddenly, the division between types that are passed “by reference” and ones that are inexplicably passed “by value” makes complete sense.

I am happy that I noted that I was confused and expressed my confusion despite feeling embarrassed.
After trying several functions in the Julia REPL and determining that the behavior did indeed break my mental model (I felt so confused),
I asked one of my mentors for the summer the relevant question.
Once I convinced him that I was in fact not joking and was honestly surprised and confused,
he was very patient about correcting my misunderstanding.
Being very confused about a fundamental aspect of programming,
misunderstanding such a seemingly basic thing,
was embarrassing to admit to myself;
it was much more embarrassing to reveal that mistake in front of someone as awesome as him.
I still feel embarrassed, but the world also makes a lot more sense, which is worth it.

Footnotes

  1. Except in certain circumstances in C++.

Writing FizzBuzz in Julia

One of the simplest first programming exercises to try in a new language
is the FizzBuzz problem.
It’s a simple toy problem that is less trivial than “Hello, World”
because it also involves using basic control-flow structures.

This blog post assumes that you’ve already installed the Julia programming language (hint: see GitHub)
and figured out how to open a REPL (hint: run julia).

Now that you’ve got a Julia REPL open, let’s go through the very basic syntax of the language:
its control flow structures.
After we have those under control, you’ll write FizzBuzz in Julia.

If Statements

Julia uses the keyword end to end blocks rather than using whitespace or curly braces ({}) as delimeters.
Julia is not whitespace sensitive.

A simple if statement:

julia> if 5 == 4
         print("hello world")
       end

== is the equality operator; it returns either true or false.
It is both an infix operator and a function.

The simplest possible if-statements are:

if false
end

and

if true end

Julia is not whitespace sensitive;
you can sometimes put things all on one line without changing the meaning.
This is the case with these very simple if-statements.

The tricky part to guess in the if-statement syntax is the keyword elseif,
since there’s so much variation in that keyword between languages.

julia> if 5 == 6 # this is a comment
         print("five and six are equal")
       elseif mod(5,6) == 4 # you will need the mod function later
         print("five mod six is four")
       else
         print("Stefan is awesome")
       end
Stefan is awesome

For Loops

The most straight-forward ways to write FizzBuzz involve for-looping over a range of numbers,
so here’s an example of that style of loop and its output:

julia> for x=1:5
         println(x)
       end
1
2
3
4
5

Note that the range 1:5 is inclusive; both 1 and 5 appear in the output.

As you would expect, Julia also has while loops:

julia> while false
         print("something is very wrong")
       end

Ranges

The 1:5 in the for loop is a range.
Ranges are of the form start:end.
As you can see, both the start and the end are inclusive. (both 1 and 5 are values in the range 1:5)
By default, the range increments by 1.

julia> for x=1:2:10
         println(x)
       end
1
3
5
7
9

In this more complex form of range, you have start:step:end.
The end value of the range does not have to be included; it is only included if incrementing by step lands on it.

Exercise: FizzBuzz in REPL

Now that you have if statements, for loops, and the println, mod, and == functions
at your disposal, you can write FizzBuzz in the REPL.
It should take the form of a for loop with an if statement inside.

For those unfamiliar with it, FizzBuzz is a common coding problem that involves printing something
for each of the first 100 positive integers.
You should have 100 lines of output: one for each integer.

What you print depends on the number, as follows:

  • If the number is divisible by 3, print ‘Fizz’.
  • If the number is divisible by 5, print ‘Buzz’.
  • If the number is divisible by both 3 and 5, print ‘FizzBuzz’.
  • If none of the above apply, just print the number.

In case the above explanation is unclear, the correct output for 1:20 is:

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz

Solution

Don’t peek before trying it yourself, but if you feel the need to see a correct solution,
you can find one here on RosettaCode.

Using TCP Sockets in Julia

This post was updated on June 28, 2013 to reflect changes in the TcpServer/TcpSocket api in Julia.

Recently, I’ve been writing the
WebSockets implementation for Julia.

TcpSockets were not well documented
when we started using them,
so I figure a tutorial might be useful
for anyone else who might want to use TCP sockets in Julia.

REPL server

I’m still figuring out this “try things out in the REPL first” thing
(due to usually using compiled languages),
but here’s a first example of how you might play with TCP sockets
in the Julia REPL (on the right) and netcat in another terminal (on the left).

terminal1 terminal2
$ julia
> server = listen(8080)
TcpServer(listening)
> conn = accept(server)
$ nc localhost 8080
TcpSocket(connected,0 bytes waiting)
> line = readline(conn)
hi
“hi\n”
> write(conn, "Hello")
Hello 5
> close(conn)
$ false

The code-formated parts are what you type.
The normally-formated parts are what the computer prints.

Basically, you start julia, and open a TCP server for listening.
You can only accept connections on a TcpServer, not write or read.

After creating a TcpServer, you wait for a connection to accept.
At this point, you’ll need to switch terminals and open a connection from netcat.
(You can switch the order of accept and starting netcat.)

Notice that accept returns a TcpSocket.
We can do two things with a TcpSocket: read or write.

Using readline, we can block until we get a full line from the connection.
In order to stop blocking, you’ll need to enter a line in netcat.
You need to press enter in netcat for readline to return in Julia.

You can also write text to the TCP connection from Julia.
The write function takes a TcpSocket and a string to write.
The text you write from Julia will appear in netcat, as expected.

You can call close on a TcpSocket to close the TCP connection.
Closing the TCP connection makes the netcat session close.

Echo Server

A very simple server to run over TCP is an echo server.
Each time you send this server a line of text,
it will repeat that line back to you.

Here is the entire file:

server = listen(8080)
while true
  conn = accept(server)
  @async begin
    try
      while true
        line = readline(conn)
        write(conn,line)
      end
    catch err
      print("connection ended with error $err")
    end
  end
end

Running the example

Put this file in echoserver.jl.
Then, you can run it with julia echoserver.jl.

With the server running, open up netcat again (nc localhost 8080).
Type in some text and press enter.
You should see the same text printed again under what you typed.

The structure of the server

The core of this server is a pair of while true loops.
The outer one accepts each incoming connection.
The inner one reads lines from the client and echos them.

The try catch block catches any error thrown in the while loop.
The thrown error is bound to err.
The $err in the string literal is how you embed values in Julia strings.

Given two strings, s1 and s2, "$s1$s2" would be their concatenation.
You can also embed arbitrary Julia expressions: "$(2+2)" would be "4".

Handling Multiple Connections: @async

@async is a macro. It affects the begin to end block that directly follows it.
@async starts a new coroutine to handle the execution of the block.

Coroutines are like threads in that there are multiple threads of execution in the program at once,
but do not involve concurrent execution.
Only one coroutine is running at once, but the language runtime switches between them.

This means that the main connection-accepting routine will see the @async block return immediately.
This allows the outer while loop to continue accepting connections, while another routine handles each existing connection.

If you remove the @async part, your echo server will only deal with one client connection at a time.
You can test this using two (or more) instances of netcat, each in their own terminal window.

Inside the @async block, we’re in a new coroutine.
We can sit in our while true loop for as long as we want without affecting the server’s ability to accept connections.

Coroutines have very low overhead, so making a new one for each connection is reasonable.
Webstack.jl works on this same one-thread-per-connection principle.

Basic TcpSocket API

  • listen(8080) binds a TcpServer to a socket listening for connections on port 8080.
  • accept(server) blocks until there is a connection to accept on server, then accepts it and returns a TcpSocket.
  • readline(conn) blocks until a complete line comes in on conn, then returns it.
  • read(conn,Uint8) blocks until there is a byte to read from conn, and then returns it.
    You can use convert(Char,u) to convert a Uint8 into a Char. This will let you see the ASCII letter for the Uint8 you read.
  • read(conn,Char) blocks until there is a byte to read from conn, and then returns it.
  • write(conn,line) writes line to conn.