The Avail Programming Language

Method to my madness

Again another previously written blog. This one starts us down the path of actually doing things with Avail. Behold, methods blog circa February 2013.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I find that some of the best knowledge is actionable knowledge. It's great to know things, but I personally find that I'm better at holding onto a tidbit if I can do something with it. A few posts ago I realized I had been writing about my experience with Avail as if every person reading my posts understood both Avail as well as computer programming in general. So I took a step back and started talking about some important concepts in computer programming as a whole, that, as it so happens, are also particularly important to Avail. Now we can sit around and talk about types and type systems at each other all day long. I guess it's cool to stop there, if just knowing stuff is really your thing. But, I think I'd be remiss if I didn't take it one step further and actually talk about doing something in Avail. In programming, the doing and the knowing generally go hand in hand, so lets get on with the doing.

As of right now it isn't going to be easy for you to go about the doing as Avail isn't available for download yet. There are a few i's we have to dot and a couple of t's to be crossed. Aka, licensing needs to be resolved (believe me, we'd much rather be programming) and we need to touch up the programming environment in order to make the Avail programming experience rival the experience of a dog fight in outer space. So what I'm saying about the doing is, just for the moment, you'll have to take my word for it. I know Levar Burton would. Ok, lets get going with this episode of Reading Rainbow.

I may have said it before, but I'll say it again, Avail is an operation-oriented language. You do things by doing things. That is, you make things go through the use of an operation (think back to riding a bike or eating a scone). In Avail you perform operations through the use of methods. A method is an instruction that has been defined in Avail that indicates how some action should be performed. Once a method is defined, it can be referred to in an Avail program in order to do the thing you designed it to do.

A method has four components: 1) the name, 2) the parameters, 3) the return type, and 4) the function body. The first three components combined are referred to as the method signature. The method signature gives you all of the descriptive information pertaining to the method. The function body gives you the implementation of the method.

The name is simply what the method is called. For example, "_÷_" is the method name for division (the part inside the quotes constitutes the name). The name is the alias for the steps that make up the definition of the method. When you refer to that alias, the Avail virtual machine (the thing that makes avail go, hence forward referred to as vm) knows you mean the instructions contained within the method definition. This keeps you from having to fill your program with lines upon lines of instruction steps contained in the method (program instructions, the syntax, will henceforth be referred to as code). This is a universal feature in programming languages. If this wasn't done, it would make programming a horrible endeavor as you would have to rebuild everything every time you set out to do something.

The parameters of a method are the types of the inputs. They are represented by the underscore, _, in the method name (the underscores of the division method, "_÷_", are replaced with inputs when actually using the operation: "10 ÷ 5"). Not all methods have inputs, but the general expectation is that the inputs will be used in the calculation of the method in some way. If you were to add two numbers using the addition method, "_+_", your two inputs would both be of type number.

Of course, it is important to point out that the addition operation will ultimately be performed on two values, not the parameter types of the input indicated in the method signature. Now I don't want you to draw the conclusion that types are not values, because they are. Just about everything in Avail is a value. You know you are dealing with a value because it is something you can do something with, operate on, or pass to a method. In fact, everything in Avail that you'll work with as an Avail programmer is a value. As you'll see in future posts, you can do things with types. To bring it back to parameters, the parameters of a method indicate which types are accepted by the method, and thus every value that can ultimately be operated on by that method (type instances are the values represented by that type).

The actual output of a method that has been run is known as the return value. The definition of a method contains a type that indicates the expected type of that return value. This is the return type. In the same way the method parameters tell you what types of input the method will accept, the return type indicates what type of output the method will provide. For the addition of two numbers, we'd expect the output of the addition to be another number, thus we would define the return type for the addition method to be of type number. It is important to note that not all methods actually return usable values. The purpose of the method maybe to achieve some sort of side effect. An example of this would be to print something to the screen. No usable value is returned, but as a side effect of the method, something is printed to the screen. There is a lot more going on here than I've indicated so far, but I will talk about that in depth another time.

The final component, the function body, is the code (set of instructions or steps) that tells you what the method actually does. That is, how do you do what is being asked. For example, if I asked you to make me a peanut butter and jelly sandwich, you would accomplish this by following these steps:

Go to the kitchen and get the bread, the jar of peanut butter, the jar of jelly, a butter knife, and a plate. Open the bread bag and retrieve two slices of bread, put them on the plate. Open the peanut butter jar and open the jelly jar. Dip the butter knife into the peanut butter jar and retrieve peanut butter. Spread peanut butter on one of the slices of bread. Dip the butter knife in the jelly jar and retrieve jelly. Spread jelly on the other slice of bread. Adjoin the two slices of breads together with the peanut butter and jelly facing in toward each other.

With those steps, we have defined the method, "make me a_and_sandwich". The inputs of this method are peanut butter and jelly and the output is a tasty sandwich for me to eat! The steps to make the sandwich are the function body. In fact, all those steps we used to define the making of my sandwich are, themselves, other methods (ones already defined). Hence methods are built using other methods. In fact, methods are generally brought together to interact in such a way that they perform a task that is more complex than they can perform alone. And thus software is born.

Moving forward, when I discuss methods, I will introduce them using their method signature. The way I present the signature will tell you 1) what the method is called, 2) what types it takes as input, and 3) the expected type of the output. I'll do this when showing the entire function body of the code is unnecessary for the purpose of the discussion. Using the division method, "_÷_", as an example, I present the signature of this method as:

"_÷_" : [number, number]→number

The way to read this is: blank divides blank takes two numbers as inputs and produces a number. As I indicated before, the underscores represent the inputs of the method. The types in the brackets following the colon represents the types of the inputs. Note that there are as many input types as there are underscores in the method name as we need to provide a type for each input. The order of the listed input types should match the order of their underscore's position in the method name. Unlike addition, division operation does not have the commutative property, so the order of the inputs does matter. We cannot assume the input types are interchangeable. This is more evident in the operation, "The_eats the_". The dog eats the treat has a very different implication if you reverse the order of the inputs.

And now for the moment you've been waiting for, let's actually take a look at the construction of a method as it would appear in an Avail program. For our first method, we'll use the division method. I'm going to avoid showing the guts of the method (the function body) as they aren't really important for this first demonstration. Also note any green text to be found bound by /*…*/ are called comments. This is documentation that the Avail vm ignores as if it were not present. Comments are used to help the programmer remember what something does as well as convey to anyone else the purpose of that bit of code. Comments can be placed just about anywhere.

Public method "_÷_" is [ /*The method starts with the ordered listing of the input types and the variable name associated with that input type. We refer to the inputs using these variable names. The input variable name is separated from the input type using a colon. The list of inputs are separated using commas. The final input listed does not have a comma after it.*/ /*the first input corresponding to the first underscore of the method name. The number being divided into; the numerator*/ dividend : number, /*the second input corresponding to the second underscore of the method name. The number partitioning the other; the denominator*/ divisor : number /*The list of inputs is separated from the instructions using a pipe, |. */ | /*Here is where all the code that defines the method should go*/ …instructions… ]: number; /*the return type; the type of the quotient*/

Here is that method again but with all the comments stripped out so you can see it more clearly:

Public method "_÷_" is [ dividend : number, divisor : number | …instructions… ]: number;

Ok, to close out this post, we'll write a simple method that adds two numbers and returns the answer. But before the answer is returned out of the method, we want to let the world know the answer by printing it to our screen.

Public method "tell the world what you get when you add_and_" is [ /*the inputs; the numbers being added*/ input1 : number, input2 : number | /*Let's add those numbers and store them in a variable. I am declaring a new variable here, sum. As you can see, I have indicated that the type of this variable is number. I do this by placing a colon after the variable name then indicating the variable type. The ":=" tells the vm that we will be storing the result of the following method call into our new variable, sum. We conclude this expression with a semicolon*/ sum : number := input1 + input2; /*Tell the world the answer with your print statement!*/ Print: "Hello world! When you add “①” to “②” you get “③”.\ \| Just thought you should know!" with input1, input2, sum; /*The contents of the variables, input1, input2, and sum will replace the “①”, “②”, “③” in the actual print statement on screen. The end of the first line, "\", and the start of the next line, "\|" is how you break up strings over multiple lines ignoring whitespace between "\" and "\|", so the string won't have line breaks.*/ /*Finally, we return the result of our addition. Note how there is no semicolon after the variable sum. This indicates to the vm that this is the value that should be returned from this method once this method is complete*/ sum ]: number; /*To conclude, we tell the Avail vm that it can expect a number as output from from this method*/

That method will actually work in Avail as it follows actual Avail syntax. Making a call to this method with the numbers 10 and 20, and storing it into the variable, answer, looks like:

answer : number := tell the world what you get when you add 10 and 20;

The outcome of this call is that we store the number 30 into the variable, answer. The method triggers another action through the side effect, the print statement. As a consequence of this call, the monitor shows the sentence:

Hello world! When you add 10 to 20 you get 30. Just thought you should know.

That about sums up our introduction to methods. Now you should be able to go off and construct simple methods on your own. Share your new methods with your family! Show them to your neighbors! Go off and write methods and be merry!

In my future conversations, the complexity of the method definitions will undoubtedly increase as they will aim at doing more complex and interesting things. For now, I'll leave you with our add/ print method without the comments so you can see the flow of the Avail code.

Public method "tell the world what you get when you add_and_" is [ input1 : number, input2 : number | sum : number := input1 + input2; Print: format "Hello world! When you add “①” to “②” you get “③”.\ \| Just thought you should know." with input1, input2, sum; sum ]: number;

NOTE: The input types as well as the return type indicated are the least specific thing expected in the respective location of the method. More specific types can be input as well as occur as a result of the operation, however less specific types cannot. Given your knowledge of types and type systems, think about why this is the case. Don't worry if you're not sure what the consequence of this might be as I will be treating this very thing in detail in yet another post.

‹ Previous | Return to Rich's Blog | Next ›