Get rid of the separate opt-in IO class and replace it with a core
System class.
- Remove wren_io.c, wren_io.h, and io.wren.
- Remove the flags that disable it.
- Remove the overloads for print() with different arity. (It was an
experiment, but I don't think it's that useful.)
- Remove IO.read(). That will reappear using libuv in the CLI at some
point.
- Remove IO.time. Doesn't seem to have been used.
- Update all of the tests, docs, etc.
I'm sorry for all the breakage this causes, but I think "System" is a
better name for this class (it makes it natural to add things like
"System.gc()") and frees up "IO" for referring to the CLI's IO module.
The .count getter on string returns the number of code points. That's
O(n), but it's consistent with the rest of the main string API.
If you want the number of bytes, it's "string".bytes.count.
Updated the docs.
Fixes 68. Woo!
Now that I'm starting to write a real async scheduler on top of Wren's
basic fiber API, I have a better feel for what it needs. It turns out
run() is not it.
- Remove run() methods.
- Add transfer() which leaves the caller of the invoked fiber alone.
- Add suspend() to return control to the host application.
- Add Timer.schedule() to start a new independently scheduled fiber.
- Change Timer.sleep() so that it only transfers control to explicitly
scheduled fibers, not any one.
* Eliminate "new" reserved word.
* Allow "this" before a method definition to define a constructor.
* Only create a default constructor for classes that don't define one.
Had to add a new metaclass for Object since it now has its own static method so we
can't just use Class as its metaclass. (We don't want *every* class to have a same(_,_)
static method.)
The methods Sequence.map and Sequence.where are now implemented using
deferred execution. They return an instance of a new Sequence-derived
class that performs the operation while iterating. This has three main
advantages:
* It can be computationally cheaper when not the whole sequence is
iterated.
* It consumes less memory since it does not store the result in a newly
allocated list.
* They can work on infinite sequences.
Some disadvantages are:
* Iterating the returned iterator will be slightly slower due to
the added indirection.
* You should be aware that modifications made to the original sequence
will affect the returned sequence.
* If you need the result in a list, you now need to call Sequence.list
on the result.
This is a bit of a style preference since of course you can always write
the same thing with a for loop. However, I think sometimes the code
looks better when using this method.
It also provides an alternative to Sequence.map for cases where you
don't need the resulting list, and one that becomes especially necessary
when Sequence.map is changed to return a new sequence. The example in
the README.md file was using Sequence.map in a way that required this
alternative in that case.
When possible, they return the actual value from the predicate
instead of always just "true" and "false". This matches && and ||
which evaluate to the RHS or LHS when appropriate.
- "\x" escape sequence to put byte values in strings: "\x34"
- String.byteAt(index) gets value of byte in string.
- String.bytes returns a raw sequence of bytes for a string.
- String.codePointAt(index) gets the code point at an offset as a raw number.