- Remove List.new(_). I was convinced by the issue discussion that
using it is probably a bad idea. We don't want to encourage more nulls
in the world than there are already are. So let's see if we can live
without it and just have List.filled(). That way users think about
what they're creating a list *of*.
- Added some more tests.
- Correctly handle being given a negative size.
Previously, you could get into a state where a key was present in the
map, but after a tombstone in the probe sequence. If they key was added
again, it stopped at the first tombstone and added it there, resulting
in the key being in the map multiple times.
Fix#373.
This is not implemented on Sequence because, at least for lists and
strings, I think users expect an eager result. Multiplying a string
should give you back a string, not a lazy sequence of repeated
characters.
This also mirrors "+" on strings and lists, which is eager. I like the
idea of having a general guideline that operators are eager.
Repetition is useful for arbitrary sequences, but for that maybe we
should add a "repeat()" method.
This allows "%(...)" inside a string literal to interpolate the
stringified result of an expression.
It doesn't support custom interpolators or format strings, but we can
consider extending that later.
Instead, Fn.call(...) is a special *method* type that has the same
special sauce. The goal is eventually to get rid of the primitive
result type entirely.
- Add Fiber.transferError(_).
- Primitives place runtime errors directly in the fiber instead of on
the stack.
- Primitives that change fibers set it directly in the VM.
- Allow a fiber's error to be any object (except null).
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.
If a test expected an error and found at least one, it would not fail
on any other expected errors that didn't occur.
Also, some tests were expecting a compile time error message even though
the test script doesn't validate those (yet).
The test function was getting monolithic, so I went ahead and split it
into a separate little class.
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.