From 21efd111f0f3a9dec151f9696e4a47572be1e1f4 Mon Sep 17 00:00:00 2001 From: Ehren Metcalfe Date: Thu, 31 Oct 2024 15:44:49 -0400 Subject: [PATCH] README --- README.md | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d514c4b..13cb2b0 100755 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ defmacro ([x, for (y in z)], x, y, z: return quote([unquote(x), for (unquote(y) in unquote(z)), if (True)]) ) +# metaprogramming in ceto/C++ templates rather than procedural macros is recommended: + def (maybe_reserve, vec: mut:[T]:ref, sized: mut:auto:ref:ref: vec.reserve(std.size(std.forward(sized))) ) : void:requires:requires(std.size(sized)) @@ -68,12 +70,17 @@ include include (macros_list_comprehension) +# You can also do your metaprogramming by omitting the type annotations! +# Classes have immutable shared reference semantics by default +# (A class with generic data members is implicitly a C++ template class: +# - like an immutable by default Python 2 with good C++ interop/baggage and more parenthesese) + class (Foo: data_member def (method, param: - std.cout << param.size() << "\n" - return self + std.cout << param.size() << std.endl + return self # implicit +1 refcount (shared_from_this) ) def (size: @@ -81,10 +88,19 @@ class (Foo: ) ) -def (calls_method, f: - return f.method(f) +# A non type-annotated ceto function is implicitly a sligtly more +# unconstrained/generic than default C++ template function +# (calls_method's arg is generic over all ceto class types and structs +# because "." is a maybe autoderef) + +def (calls_method, arg: + return arg.method(arg) ) +# Unique classes are implicitly managed by std.unique_ptr and use cppfront inspired +# move from last use. Instance variables may be reassigned (allowing implicit move) but +# point to immutable instances (aka unique_ptr to const by default) + class (UniqueFoo: consumed: [UniqueFoo] = [] @@ -92,26 +108,35 @@ class (UniqueFoo: return self.consumed.size() ) + # For all classes and structs, a method that mutates its data members must be "mut". + # Note that "u" is a passed by value std::unique_ptr in C++ def (consuming_method: mut, u: UniqueFoo: + + # u.consuming_method(None) # Compile time error: + # "u" is not a UniqueFoo:mut so a "mut" method call is illegal # "u" is passed by reference to const to the generic method "method" here. Foo(42).method(u) - # The last use of a :unique instance is std::move'd automatically. - # This is heavily inspired by the feature/idea in Herb Sutter's cppfront: - self.consumed.append(u) + self.consumed.append(u) # Ownership transfer of "u" on last use (implicit std.move) ) ) : unique +# std.string and vectors (implicit use of std.vector with square brackets) passed +# by reference to const by default: def (string_join, vec: [std.string], sep = ", "s: if (vec.empty(): return "" ) + # Explicit lambda capture brackets required for + # unsafe (potentially dangling) ref capture: return std.accumulate(vec.cbegin() + 1, vec.cend(), vec[0], lambda[&sep] (a, b, a + sep + b)) ): std.string +# defmacro param types use the ast Node subclasses defined in selfhost/ast.cth + defmacro (s.join(v), s: StringLiteral, v: return quote(string_join(unquote(v), unquote(s))) ) @@ -122,7 +147,9 @@ def (main, argc: int, argv: const:char:ptr:const:ptr: args = [std.string(a), for (a in std.span(argv, argc))] summary = ", ".join(args) - f = Foo(summary) # in C++ f is a const std::shared_ptr> + f = Foo(summary) # implicit make_shared / extra CTAD: + # in C++ f is a const std::shared_ptr> + f.method(args) # autoderef of f f.method(f) # autoderef also in the body of 'method' calls_method(f) # autoderef in the body of calls_method (and method) @@ -137,11 +164,11 @@ def (main, argc: int, argv: const:char:ptr:const:ptr: std.cout << fut.get() - u: mut = UniqueFoo() # u is a (non-const) std::unique_ptr<"non-const" UniqueFoo> in C++ - u2 = UniqueFoo() # u2 is a (non-const) std::unique_ptr in C++ + u: mut = UniqueFoo() # u is a "non-const" std::unique_ptr in C++ + u2 = UniqueFoo() # u2 is a non-const std::unique_ptr in C++ u.consuming_method(u2) # Implicit std.move from last use of u2. - # Note that :unique are non-const (allowing move) but + # :unique are non-const (allowing move) but # unique_ptr-to-const by default. u.consuming_method(u) # in C++: CETO_AUTODEREF(u).consuming_method(std::move(u))