TeaScript 0.17.0 was published on the 16th August in 2026 and can be downloaded for free:
| TeaScript C++ Library | TeaScript_CppLibrary_v0.17.0.zip |
| TeaScript Host Windows | TeaScript_v0.17.0_win64.zip |
| TeaScript Host Linux (Ubuntu 22.04) | TeaScript_v0.17.0_linux64.tgz |
All details, features and changes for this new release are following in the blog post below.
Infos and Links
The download page with more infos, links and basic instructions:
βββ Download Page. βββ
Browse the source code of the TeaScript C++ Library on Github.
Read the changelog.txt for a detailed list of all changes.
Are you new to TeaScript? Then you may read here first: Overview and Highlights of TeaScript.
Watch demos, tutorials and more on the YouTube Channel.
What was new?
The previous release blog posts are nice for a tutorial like introduction of the new features and for getting an overview. If you missed some, here is the collection.
- Release of TeaScript 0.16.0 π β Error type, catch statement, default shared params, BSON.
- Release of TeaScript 0.15.0 β β Web Server / Web Client module preview, full JSON read/write support.
- Release of TeaScript 0.14.0 π₯ β TeaStackVM, Compiler, Dis-/Assembler, Suspend+Continue, Yield, improved debugging.
- Release of TeaScript 0.13.0 π β Buffer, U8, U64, bit ops, UTF-8 Iterator, hex integrals, MPL-2.0.
- Release of TeaScript 0.12.0 π β Colored Output, Format String, Forall Loop, Sequences, interactive debugging.
- Release of TeaScript 0.11.0 π β TOML Support, Subscript Operator, Raw String Literals.
- Release of TeaScript 0.10.0 π β Tuples/Named Tuples, Passthrough Type, CoreLib config.
What is new?
The TeaScript 0.17.0 release comes with the following new main features:
- a new Map type with arbitrary keys and values as an additional container type to the already existing Tuple/Named Tuple.
- a try statement similar as in Zig, extending the modern Error handling.
- a reflection extension based on reflect-cpp for reflecting structs from/into TeaScript's Named Tuples.
The new Map type led to the πΊ map symbol for this release. Unfortunately, not with every font it really looks like a map.
All new features are explained below.
Map type
TeaScript now has a distinct Map type for mapping arbitrary keys to arbitrary values.
The main difference to Named Tuples:
- The key can be any type and is not restricted to
String. - The values are ordered by the keys (ascending).
- a dot operator does not exist.
- the subscript operator takes the key only - no access by index.
- maps are printed with enclosing
{}instead of().
Internally the Map is implemented simply as std::map<ValueObject, ValueObject>.
The forall loop was extended to loop over all keys in a map in an handy, convenient way. A map iterator is created on the fly when starting the forall loop and is advanced on each loop iteration (see examples below).
This release also adds a lot of map related utility functions: _map_create, _map_size, _map_contains, _map_at, _map_remove, _map_insert, _map_assign, _map_insert_or_assign, _map_keys, _map_values and _map_kv_tuple.
See Documentation Map Support.
Here are some examples of how to use the Map:
// creating a map with 3 key value pairs (key is always i64 here).
def map := _map_create( (2, 6), (5, "Hello"), (9, (1,2,3) ) )
_map_size( map ) // 3
_map_contains( map, 1 ) // false (key 1 does not exist)
_map_contains( map, 2 ) // true (key 2 does exist (with value 6))
_map_at( map, 2 ) // 6
_map_at( map, 5 ) // "Hello"
_map_at( map, 9 )[2] // 3
_map_at( map, 23 ) catch( err ) { println( err ) } // prints "Map At: Key does not exist!"
// subscript operator
map[ 2 ] // 6
map[ 2 ] := 42 // assigned 42 at key 2
map[ 2 ] // 42
//map[ 3 ] // Would throw a C++ 'exception::eval_error'!
map[ 3 ] := 123 // inserted key 3 with value 123
_map_size( map ) // 4 (one new element was inserted)
// forall loop with the map iterator
forall( it in map ) {
println( "at idx %(it.idx): key=%(it.key), value=%(map[ it.key ])" )
}
// the loop above prints:
// at idx 0: key=2, value=42
// at idx 1: key=3, value=123
// at idx 2: key=5, value=Hello
// at idx 3: key=9, value=(1, 2, 3)
// remove an element
_map_remove( map, 3 ) // key 3 with value 123 is now gone (map size == 3)
// assign and insert
_map_assign( map, 2, 777 ) // value for key 2 is now 777, equivalent to:
// if( _map_contains( map, 2 ) ) { map[2] := 777 }
_map_insert( map, 17, "Foo" ) // new element with key 17 and value "Foo", equivalent to:
// if( not _map_contains( map, 17 ) ) { map[17] := "Foo" }
// _map_insert_or_assign is equivalent to map[ key ] := value
// but returns true for insert and false for assign.
_map_insert_or_assign( map, 5, "Hello World!" ) // false b/c assigned to an existing key and not inserted new
// key value utilities
def keys := _map_keys( map ) // (2, 5, 9, 17) as deep copy, keys in a map cannot be changed.
def values := _map_values( map ) // (777, "Hello World!", (1, 2, 3), "Foo")
// as shared values, change one in this tuple it will be changed in the map as well.
def kv := _map_kv_tuple( map ) // ((2, 777), (5, "Hello World!"), (9, (1, 2, 3)), (17, "Foo"))
// keys are deep copied, values are shared with the map values.
forall( idx in kv ) {
println( "at idx %(idx): key=%(kv[idx][0]), value=%(kv[idx][1])" )
}
//at idx 0: key=2, value=777
//at idx 1: key=5, value=Hello World!
//at idx 2: key=9, value=(1, 2, 3)
//at idx 3: key=17, value=Foo
The order of the elements is (actually) always in ascending order of the keys, regardless in which order the keys are inserted.
// start with an empty map...
def mymap := _map_create()
_map_insert( mymap, "zebra", 123 )
_map_insert( mymap, "jellyfish", 789 )
_map_insert( mymap, "ant", 456 )
_map_insert( mymap, "duck", 321 )
println( mymap ) // prints: {("ant",456), ("duck",321), ("jellyfish",789), ("zebra",123)}
The keys of one map instance can be of mixed types as long as they are comparable with each other, e.g., you can combine i64, u64, u8, f64 and even String in one map as long as the string converts to a number.
// multi key types
def newmap := _map_create( (2, 7), (5u8, "Hello"), (9u64, (1,2,3) ), ("17", _buf(4) ) )
_map_at( newmap, 5u8 ) // "Hello"
_map_at( newmap, 5i64 ) // "Hello" (compares same to 5u8 although it is a different type)
_map_at( newmap, "17" ) // [] (empty buffer)
// checking type of each key...
forall( it in newmap ) {
println( "key=%(it.key) with type=%(typeof it.key)" )
}
// prints:
// key=2 with type=i64
// key=5 with type=u8
// key=9 with type=u64
// key=17 with type=String
// Now trying to insert a new element with a key which is not comparable with the existing keys.
// key is of type Buffer here.
_map_insert( newmap, _buf(1), 123 ) catch( err ) { println( err ) }
// prints: Map Insert: Key is not comparable with existing keys!
See also the unit test for the Map and the utility functions corelibrary_test07.tea and the example_v0.17.tea script for more code examples.
Container types in TeaScript
With the new Map type TeaScript now has these container types:
- Tuples: as tuple, list, array, queue, stack.
- Named Tuples: dictionaries and C-like structs. (See Named Tuples )
- Buffer: raw bytes in memory. (See write image example )
- String: UTF-8 glyph and byte accessible strings.
- Map: sorted key-value container with arbitrary keys.
These can then be combined with the TOML and JSON (+ BSON) support as well as the new reflection feature of this release (see below).
Try Statement
In the last release 0.16.0 TeaScript introduced the Error type together with the catch statement (see Catch.)
The catch statement was highly inspired by Zig, so is the new try statement of this release (see Zig try.)
The try statement is roughly equivalent to stmt catch( err ) { return err }, but has some advantages in execution compared to the fully written catch variant since it does not need to store the Error by name in the variable storage and look it up again from there.
See the following examples:
// just some test function reading input from a file and returning the content as an absolute number
func get_number_from_file( file )
{
def content := try readtextfile( file )
def number := try _strtonum( content )
abs( number )
}
// this will fail, there is no foo.txt
def result01 := get_number_from_file( "foo.txt" ) catch( err ) { println( "Error: " % err ) }
// prints: Error: Cannot open/read file!
// write some file with faulty data
writetextfile( tempdir() % "foo.txt", "abc", true, false )
def result02 := get_number_from_file( tempdir() % "foo.txt" ) catch( err ) { println( "Error: " % err ) }
// prints: Error: Could not convert to Integer!
// write some file with correct data
writetextfile( tempdir() % "foo.txt", "-123", true, false )
def result03 := get_number_from_file( tempdir() % "foo.txt" ) catch( err ) { println( "Error: " % err ) }
if( result03 is Number ) {
println( "result03 is number %(result03)" )
} else {
println( "result03 is NOT a number!" )
}
// prints: result03 is number 123
Reflection Extension
C++ only
TeaScript now has a new optional extension for reflecting C++ structs (yes, C++, not pure C) into (Named) Tuples and reflect from Named Tuples into C++ structs.
This is currently (see Outlook for a possible future variant) realized with the help of reflect-cpp. It was tested with version 0.23 as well as 0.25 (the latest at the time of writing).
See the full source code example of the included demo (=example) project.
After compilation, run it via teascript_demo[.exe] reflect.
In order to use this extension via the TeaScript C++ Library, you must do the following:
- Download the reflect-cpp source from reflect-cpp on Github
- Add extensions/include of TeaScript to the include paths.
- Add the 'include' directory of reflect-cpp to your include paths.
- Add the 'src' (yes, src, no typo!) directory of reflect-cpp to your include paths.
- Either add extensions/source/Reflection.cpp to your project or add an #include "reflectcpp.cpp" to an already existing TU.
- Include "teascript/ext/Reflection.hpp", use the feature in your code and compile.
Imagine you have the following C++ struct and instance:
// some C++ struct (note the self reference in children)
struct Person
{
std::string first_name;
std::string last_name;
int age{0};
std::vector<Person> children;
};
// create an example instance of the C++ struct.
auto homer = Person{.first_name = "Homer",
.last_name = "Simpson",
.age = 45};
homer.children.emplace_back( Person{"Maggie", "Simpson", 1} );
homer.children.emplace_back( Person{"Bart", "Simpson", 10} );
If you want to use a copy of homer in TeaScript you can reflect it into TeaScript without macros, registration or other prerequisites like this:
// create the default teascript engine.
teascript::Engine engine;
// import the C++ struct instance into TeaScript.
teascript::reflect::into_teascript( engine, "homer", homer );
// nothing more to do, that's all!
Now, within TeaScript we can use 'homer':
tuple_print( homer, "homer", 10 ) // prints all (nested) elements with name and value
// access some fields
homer.first_name // "Homer"
homer.age // 45
homer["last_name"] // "Simpson" (alternative way of accessing elements by key, by index and via `tuple."key name"` is also possible)
homer.children[0].first_name // Maggie
homer.children[1].first_name // Bart
// NOW modifying it by adding Lisa as a child
_tuple_append( homer.children, _tuple_named_create( ("first_name", "Lisa"), ("last_name", "Simpson"), ("age", 8), ("children", json_make_array() ) ) )
// create a shared reference to Lisa
def lisa @= homer.children[2]
Now we can reflect Lisa back into a new C++ Person struct instance via this code:
// exporting from TeaScript into a new C++ struct instance!
// !!!
Person lisa = teascript::reflect::from_teascript<Person>( engine, "lisa" );
// !!! - Thats all !
Clang compatibility issue
It turns out that clang 14 (minimum version for TeaScript) with libc++ does not compile reflectcpp version 0.25.
There are some possibilities to deal with it:
- Try a newer clang version. Since it is in the area of
std::ranges, clang 16 would be probably a good trial. - Use libstdc++ instead, it should work.
- Use reflectcpp version 0.23 instead.
- Use g++ instead.
Breaking Changes
None in this release (apart from the removals listed under Deprecation).
Deprecation
The following deprecated parts have been finally removed from this release:
class LibraryFunction0<> to LibraryFunction5<> are finally removed now.
Please, use the new and generic one fits for all LibraryFunction<> instead.
The temporary macro TEASCRIPT_DISABLE_GETVALUE_CONSTCHECK for restoring previous faulty behavior has been removed.
Please, for class ValueObject use either GetValue< Type const >() instead or the
more clean variant by calling one of GetConstValue()|GetMutableValue() or GetValueCopy().
The following parts are now deprecated and will be removed in some future release:
_f64toi64 is still deprecated.
Please, use the cast operator as instead (recommended, or alternatively to_i64).
Misc
- Removed the need to manual register Tuple as TypeInfo. (C++ low level api only)
- Made TypeInfo a first class citizen. (C++ only)
- 3rd party update: fmt 12.1.0 / nlohmann 3.12.0 (pre-built Host Application only)
- Added Map type + try keyword to syntax highlighting for Notepad++
A word about AI
Some may wonder why TeaScript is now hosted at teascript.run-by-ai.cloud.
run-by-ai.cloud is my domain, so I host TeaScript on my own domain as before with tea-age.solutions.
During the last months I engaged more and more with agentic AI. After some private projects I realized that I can dramatically increase my productivity. I have so many ideas but beside a full-time job and a family with kids there isn't much room for anything else.
AI solves this problem for me:
Get the idea down on paper (prompt/CLAUDE.md/AGENTS.md), refine and plan it together with the agent, orchestrating and supervising the realization, review and deploy/use it. Iteratively, parallel - automated when possible. The outcome is huge, the quality is awesome - when the human does his job right. AI alone is fast, human alone can do great things but we are so slow (relatively). Combine both, as a symbiosis, and it will be awesome.
Q: So, what about TeaScript then? Is TeaScript written by AI now?
A: No, not at all. TeaScript is currently and will always be 100% programmed by a human. This is my personal choice, because I love to program C++ and TeaScript. But AI helps me in all the surroundings: Get rid of Wordpress (See "The Relaunch" below), write good, readable and comprehensive documentation, helps me to semi-automate release processes, etc.
But there are and will be other projects - some of them I plan to publish, others just help me for my projects and other things - where AI is also involved in programming. And the results are good. One result is the new home of TeaScript. Read about it in the blog post The Relaunch.
This is the first release blog post added to the page with the new machinery in the backend. It does all cumbersome and error-prone tasks for me: creates and links the release table above, writes the "What was new?" section, modifies the downloads page accordingly and also creates and checks the binary checksums and adds it to the corresponding place. This always used to be long, error-prone manual work before with WordPress and often I made a mistake or forgot something. Now, everything just works.
More Infos
More information about the TeaScript language is available here:
β― Overview and Highlights
β― TeaScript language documentation
β― Core Library documentation
βββ Try and download TeaScript here. βββ
Outlook
There are a lot of possibilities for the 0.18.0 release. I have not yet decided which items I will address. Probably, the next release will focus more on internal architecture. One idea is to speed up the compiled execution in the TeaStackVM. But for this I possibly must get rid of dynamic scoping, so that TeaScript will use ordinary lexical scoping as most of the other languages. TeaScript uses dynamical scoping more by an accident than by intent. But since it has been out for some years now, users may rely on that feature.
So, my question to all of you is: Do you need dynamic scoping in TeaScript? And if yes, why/for what use case? Please, open an entry on GitHub Issues (label: feedback) if you need it and rely on it and describe your use case/need.
Furthermore, I still plan to add YAML to TeaScript to complement the existing TOML and JSON support.
Additionally, I am playing with the C++26 reflection feature of g++16. Maybe the feature of this release won't need a third party library anymore if g++16 is used for compilation.
Last but not least, there might be some extensions and/or convenient features to the Tuple, Map and Sequence ecosystem.
What do you think about this TeaScript release? What is the most important feature which is currently missing or must be improved?
I will be extremely happy for any feedback, suggestions, questions and other kind of constructive feedback.
I hope you will enjoy with this TeaScript release. :)