Welcome to turtleSpaces!
turtleSpaces projects are written in a language called Logo. Unlike game-maker applications and introductory languages such as Scratch, Logo is a complete programming language capable of realising almost anything you can think of. It is also designed to make writing complex code (and making complex applications) as simple as possible!
First, turtleSpaces Logo (tSL, pronounced ‘tea-sill’ to distinguish it from classic Logo) contains hundreds of keywords (called primitives in tSL) that do a myriad of things. But these keywords try to be as generic as possible, so that you can combine them in new and inventive ways. And there are often several different combinations of primitives you can use to accomplish a goal.
turtleSpaces Logo is largely compatible with Apple Logo II, and as such you can use books written for it to introduce you to turtleSpaces. These books are available on the Internet Archive at archive.org, such as:
https://archive.org/details/Learning_With_Apple_Logo_by_Daniel_Watt_1984 or
https://archive.org/details/Discovering_Apple_Logo_David_Thornburg or
https://archive.org/details/logoworks or
https://archive.org/details/Apple_Logo_II_Reference_Manual
There are four primary types of primitives:
Switches – these primitives, such as paging and speckle, turn on a ‘state’, or a way in which a turtle, or turtleSpaces as a whole, behaves. Typically, prefacing them with ‘no’ turns them off, such as nopaging and nospeckle. To see if they are on or off, you add a ‘p’ to the end of the switch, such as specklep, which is an primitive that returns a ‘boolean’ which is either true or false.
Settings – these primitives all start with ‘set’, such as setpencolor. You provide a value to set them to, this can either be a ‘real’ value, or ‘data’, such as 5 or “frog, a container (variable), or the output from another primitive, such as a calculator. Their value is stored in the primitive with the corresponding name without ‘set’, such as pencolor. When called, these primitives return the stored value, so ‘show pencolor’ outputs the pencolor to the screen, for example.
Calculators – these primitives typically take inputs, do calculations and return output, such as math functions like sum or sin. This output is ‘fed’ to another primitive as an input, including to other calculators.
Performers – these primitives affect the turtleSpaces environment, either by moving a turtle, drawing to the screen, printing text, making a sound, outputting to a disk or other things. These generally (but not always) take inputs, which can be data (hard facts) such as 10 or “frog, a container, or the output from another primitive. An example of a classic turtle performer is ‘forward 20’, which moves the turtle forward 20 ‘turtle-spaces’ or GL units.
Second, there are four types of data in tSL: booleans, numbers, words and lists.
Booleans are simple binary values – they can be either true or false. These are used by switches, and by comparison primitives such as equalsp or >, which are primarily used by the ‘if’ primitive, which takes a boolean value as its first input, and a list of other primitives to perform if the first input is true as its second input.
(Unlike other languages where the comparisons are made by the comparison command itself, in tSL comparison primitives return either true or false, and this output is provided to the primitive ‘if’. To see this demonstrated, type ‘show 5 = 2’ or ‘show equalsp 10 10’.)
Numbers are numbers of any value, like 123.45. They can also be negative, like -92.
Words are strings that are treated atomically – that is, as a single item. So “frog is a single word, but |The frog jumps over the creek| is also a single word (known as a ‘long word’). The former is denoted by a single quotation mark (“) at its start, the latter by being surrounded by pipe symbols (||). These are both treated as single items for the purposes of lists, which we will get to next.
Lists are lists of other data, including other lists. These are usually enclosed in square brackets [] and look something like [pig duck cow] or [Mary went for a walk]. Each individual item in the list is treated as a seperate bit of data by some primitives, while others treat the list as a whole as one bit of data.
Lists are literal. If you put [3 + 4] in a list, what you have are three items: 3, + and 4. However, if you use curly braces {} instead of square brackets, the list is evaluated at runtime – when it is parsed for execution. So {3 + 4} is evaluated as 7, and so will resolve as a list with a single item, 7. {pig} will attempt to call a primitive / procedure named pig, and if it doesn’t find it, the program will cause an error. {“pig} would be what you need to have a list item named pig, in a softlist.
These four types of data serve as the input and output of primitives. But what if you want to store a piece of data for later use? turtleSpaces has two primary methods of doing this, containers and tables.
Containers are the simplest – you take a piece of data, stick it in a container, and put a label on it to identify it, like it’s leftovers in a fridge. Due to the long, storied history of Logo there are four ways of doing this:
make “frog 5 – makes a container named “frog” and puts the value 5 in it.
name 5 “frog – sticks 5 in a container and writes the name “frog” on it.
put 5 in “frog – puts 5 in a container named “frog”.
Finally, you can simply say “frog := 5 – think of := as a happy little helper duck.
Regardless of which method you use, they all accomplish the same thing. To see what’s in a container, you simply put a colon : at the start of its name, like :frog
The show primitive displays the data that is given to it, so if we type show :frog, show will look inside the “frog” container, and then tell us what is in it, in this case the number 5.
If you make a container declaration using any of these methods and the container already exists, the value in it will be updated.
You can store multiple bits of data in a container by storing a list in it.
put [sheep cows goats] in "livestock show :livestock [sheep cows goats] show item 1 :livestock sheep
Finally, containers normally store values that were true at the time you stored them. So, if you go:
make "clock {hours minutes seconds}
whenever you print :clock it will display the time as it was when the make statement was executed. What if you always want it to display the current time? For that, use make!
No, really, the exclamation mark isn’t for emphasis, the primitive really is make! eg:
make! "clock {hours minutes seconds}
Now, whenever you print :clock, :clock is evaluated at that moment, and will always give you the current time. Neat, huh? Moving on…
Another way to store lots of data is to use a table, which is a grid that stores data in cells arranged in columns and rows. Tables are named, and their dimensions are specified as the number of rows (x), columns (y), and optionally sheets (z).
newtable “mytable [20 10] will create a new table with 20 rows and 10 columns.
newtable “mytabletoo [20 10 10] will create a new table with 20 rows, 10 columns and 10 sheets.
You use the putcell primitive to place data into a cell:
putcell "mytable [4 4] "duck
and you read the cell back using the cell primitive:
show cell "mytable [4 4] duck
There are a number of other primitives related to tables, see help “table
The third way in which tSL tries to make things easier is by being turtle-centric. Turtles themselves store containers, tables, and lists of primitives to perform known as procedures. Procedures are ordered lists of instructions, like recipes, that tell a turtle what primitives to perform and in what order.
Like a recipe, a procedure starts with the word ‘to’, as in ‘to bake bread’ in the context of a recipe, or ‘to drawsquare’ in the context of tSL. (procedure names cannot contain spaces, but they can contain underscores _)
to drawsquare forward 20 right 90 forward 20 right 90 forward 20 right 90 forward 20 right 90 end
‘end’ tells the turtle that they have reached the conclusion of the procedure. Notice that in tsL you can place multiple primitives on the same line of code.
to drawsquare repeat 4 [forward 20 right 90] end
‘repeat’ is an primitive that performs other primitives. The first item passed to repeat is the number of times to repeat the primitives, and the second is a list of those primitives.
to drawsquare repeat 4 [ forward 20 right 90 ] end
List items can be spread across multiple lines, which is handy with primitives such as repeat, but not mandatory. You can format your code either way.
There are three more things you should know about procedures. First, they can take input values, just like primitives:
to drawsquare :size repeat 4 [forward :size right 90] end
When drawsquare is called, it will require an item of data be passed to it, such as 20. This data is placed in a container called “size” – but that container only exists for the time the turtle executes the procedure, after which it is discarded. So, once the square is drawn, the “size” container no longer exists.
Second, they can output data, just like primitives:
to randomnumber output random 100 end
The randomnumber procedure is a calculator – it returns a number between 0 and 99 (random generates a number ‘up to but not including’ the number you give it). If you try to call randomnumber by itself, tSL will complain, not knowing what to do with the number randomnumber returns! To see the number, you need to show it, as in ‘show randomnumber’.
Thirdly, procedures can call other procedures!
to drawsquare make "size randomnumber repeat 4 [forward :size right 90] end
By providing the name of our procedure calculator to make, we have instructed it to go off to randomnumber, execute its instructions, then take the value it returns and put it into the “size” container. Say I asked you how many ripe tomatoes were in the garden, and you didn’t know. You would need to go out to the garden and count them, and then come back. That’s all this is – I’ve asked you how many tomatoes there are, you need to go out to the garden and look to get that number. Then you come back and tell me, and we continue deciding what to have for supper.
Now, back to the turtles. tSL comes with three primary turtles: Myrtle, Snappy and Libby. They are each unique in their own way. Myrtle is the turtle you see on the screen when tSL starts up. Myrtle is also the turtle that is selected, as indicated by the prompt in the ‘interactive’ area at the bottom of the screen. If you type ‘forward 20’ and press return, it is Myrtle who moves.
Snappy is the turtle that is looking at Myrtle – that is, you are looking through Snappy’s eyes. If you switch turtles to Snappy (by typing ‘turtle snappy’ without quotes and pressing return) and then move Snappy by typing ‘right 90’ (return), Myrtle will vanish! But Myrtle hasn’t moved – type ‘left 90’ (return) and she will come back.
You can look at the overall space through the ‘eyes’ of other turtles as well, which we will get to later. But the idea of the turtle as a camera is a powerful one you will find useful. Turtles are also lights! (Snappy is also the default light.)
Libby is the ‘library’ turtle. Other turtles can read procedures that are stored in Libby. Libby is only designed to store procedures – she cannot perform them herself.
You can create new additional turtles and call them whatever you like by using the newturtle primitive. A shorthand way of addressing them without using the turtle primitive to switch to them is to preface the primitive you wish for them to preform with their name followed by a colon. So, say I was currently working as myrtle, I could type snappy:right 90 and snappy would turn right 90 degrees.
But this raises another important point: when you call a primitive or a procedure from interactive mode, for example to start a game, you are directing the attention not of Myrtle, but of the main turtle ‘worker’ to perform what you ask. If the procedure directs another turtle to do something, the same worker will be the one that does it – it’s as if the worker is transferred to the other turtle, which then does what is needed and then transfers back to the first turtle and continues.
If you want another turtle to go off on its merry way, while the main worker continues in the current turtle, you need to use the ‘newworker’ primitive. Think of it as creating a clone worker. It acts through the same turtles inside the same space, but independently.
“But this is confusing! Why doesn’t each turtle just think for itself?” Well, synchronisation can be a bit tricky. If I need Snappy to be somewhere or do something before Myrtle does something, I would need to have Myrtle wait, then get some kind of signal from Snappy. Or I might just be lazy and assume that Snappy will be done in a certain amount of time – which can end badly, especially if Snappy and Myrtle are sharing containers, which you can do. It’s much better in those circumstances to use the same worker to do what Snappy needs to do, then return to Myrtle and continue.
Also, workers use resources on the host computer, and so having them waste space and chew CPU time unnecessarily is wasteful. And you might want to have multiple workers working through the same turtle, checking if certain conditions are true and acting accordingly, or updating things in the background, such as the turtle’s model. So making a distinction between turtles and workers is ultimately more useful than not.
Think of a turtle more as a ship than an individual entity, even if that ship often only has a single worker, or none at all. Also consider that you yourself are ultimately a worker, directing other workers, and those workers direct you, by requiring your input. These are useful things to think about.
And with that, we’ve reached the end of basic concepts. At this point it would be advisable to examine some basic projects and see how they work.
https://turtlespaces.org/docs/examples/
You can find them in the examples folder at the top of the project catalog, which you can enter using the ‘cat’ primitive (without the quotes), or control-shift-` or by clicking the Examples link in the menu bar of the Web interface.
Once you have opened an example project, you can examine all of the turtles and procedures contained within in by using the ‘ed’ primitive, or control-shift-E.
You can move the camera turtle around by left-clicking and dragging to orbit, or right-click and drag to rotate or pull in and out.
Most of the primitives have fairly straightforward names like forever, slideright that should indicate their function – for those who are somewhat ambiguous or whose parameters are, you can read up on them individually by typing help “primitivename from the interactive mode prompt.
Or you can read up on them all by using the viewref (ref = reference) primitive. Or on this website here.
The best way to discover turtleSpaces is to explore it!