About 0.14.0
I’m excited to announce that the 0.14.0 version is out with a lot of interesting new features. And since I didn’t posted a thing about “older” versions since 0.8, I’ll mention some features that shipped with them, too:
Custom types
Custom types are our way of doing what I’ll call “PUOHT” (programming using objects here and there) and now it’s easier to make them behave almost like native objects. The following methods are now available:
extract
to.string
operate
This way you have much more freedom to implement your objects without
relying on ugly shortcuts like sum $myobject 10
or print [to_string
$myobject]
or worse.
Scopes and context managers
A feature whose implementation feels very natural after you have custom types is context managers. I drew inspiration from Python and now you can write this kind of thing in Til:
type logger {
proc init (name) {
print "logger for `$name` was instantiated."
return $name
}
proc open (name) {
print "$name: starting..."
}
proc close (name) {
print "$name: closed."
}
}
scope "test the logger" {
with l [logger "teste"]
print "sleeping..."
sleep 1
}
The result would be:
logger for `teste` was instantiated.
teste: starting...
sleeping...
teste: closed.
The scope
command is going to help me implement better test suites (when
an assert
fails it can also display the scope name, for instance) and
work this way:
- variables are shared with outer scope;
- anything else isn’t.
Now the with
command acts almost like set
, in the sense that it
creates a new variable in the scope, but it also immediately calls the
open
method, while the close
method is called when the scope ends.
This combination of scope
and with
solves a problem I discussed some
months ago with dumblob
: nested context managers. In Python they are
kind of a pain in the ass, since you easily ends with too much indentation
or some horrible giant lines. In Til, the number of managers for a context
has “vertical influence” only: it’s not going to act in the horizontal
axis of your code – and you can even instantiate them outside of the
scope if you feel the need to.
(And all this is going to make my life much easier when I start working with the file system and sockets.)
Strings
Now we have regexes.
Of course, in a very early stage, but at least you don’t have to rely so
heavily on exec
.
See (and run) examples/regex.til
.
Also, one can iterate over each character of a string, now, using the
range
method, and insert some special characters, like \n
or \t
.
I still want the code for Til to be very easy to read, so I’m always trying to keep it small. Special characters in strings (and strings in general) have this tendency to need a lot of code, so I’m not planning on expanding too much on this special characters list, but simply allowing the insertion of chars by hexadecimal or “\u” notation.
Environment variables and command line arguments
Your program now has access to $env
(containing the process environment
variables) and $args
(containing the command line arguments).
Skip!
There’s both ExitCode.Skip
and the command skip
, so that your ranges
(or transform
) can ask for whoever is consuming it to skip this
iteration because there’s nothing really interesting to “yield”.
Ranges
The range
method for SimpleLists now has a sibling, range.enumerate
,
that acts like the enumerate
function from Python, returning both the
index and the item on each iteration.
There’s also the zip
command to “zip” multiple ranges together.
NO MORE AUTOMATIC PRECEDENCE!!!
That was a hard decision to make, but that still makes some sense: math and logic operations don’t apply precedence automatically anymore. I’m well aware of the potential to put off a lot of people, but this has two advantages:
- It makes the
math
code so much easier to understand; - If the user can overwrite
operate
, maybe the precedence is not aways a good thing.
So, now that you can implement different behaviors for +
and *
in your
custom type, maybe forcing *
to happen always before +
is not an
interesting behavior…
I was thinking about implementing automatic precedence in math
, but
I believe it would be very confusing to see it working in some places
(math
calls) and not working in others (if
calls, for example).
But, notice, &&
and ||
precedence still apply for logic evaluations!
Anyway, precedence is crazy. If you look how we do it in the real world you clearly can see it would never fit a computerized operation much easily, right?