Hacker News new | past | comments | ask | show | jobs | submit login
Circle: C++ Automation Language (circle-lang.org)
113 points by pjmlp on Oct 16, 2021 | hide | past | favorite | 24 comments



This project feels similar in spirit to Zig, which has robust compile time evaluation and reflection.

The cool part about Zig is that it uses this ability (via the `comptime` keyword) to power it’s generic system, and not vice versa (looking at you, Turing complete type systems)

https://ziglang.org/learn/overview/#generic-data-structures-...


Truly the Lisp-equivalent of static evaluation. So probably won’t catch on (too ad hoc, not very declarative, not exhaustive).

At least they give it a nice abbreviation like “comptime” instead of the atrocious “CTFE” that C++ seems to like.


Technically comptime makes zig Turing complete (except that you have a finite number of branches available to consume during comptime).



Circle is pretty cool. If I remember correctly, Sean didn't fork clang, but wrote his own C++ front end and then some. So one motivated person can do it, it's not insurmountable.


When coding in C++ I often thought "Why isn't there an imperative programming language in the preprocessor?"

This was the only thing holding me back from finishing my metacircular TODO app.


It's very neat but closed-source and by the looks of it is likely to stay that way. I can't see it being used in any mission-critical projects unless the source is fully disclosed and viewed/analysed by the community... until then it's a "nifty black box".


This is really neat. I've done similar things with jinja templates plus heavy use of c++ template magic - with the downside that there's a bit of disconnect between the two syntaxes. I'll have to keep an eye on this for the future.


I like circle, and Sean does a lot of great work, but I'll have to stick to more pedestrian code generation for now.

It might seem too picky to some, but I need to have good control over the inputs into my build processes. There are the obvious concerns regarding reproducibility and security which, again, maybe some don't care about. But there are also implications for distributed building and caching workflows. Circle doesn't practically drop in for C++ while it is allowed to do arbitrary I/O (even off the machine!) at build time.

It seems like it should be a solvable problem at the expense of restricting what can happen at compile time, at least as an opt-in feature.

The usual response is "well, don't do that kind of thing!", but at scale, manually maintaining that kind of design standard isn't practical. But I'm sure you all audit all the source that feeds into each one of your container base images.


Ah yes, we've come full "circle" and C++ has tacked on D's metaprogramming and CTFE abilities.


This was an explicit design intent from early days of C++. I remember discussing Lisp's macro capabilities with Stroustrup back in the early 90s and him saying he had always wanted to have that in C++ and templating was the first step.

Shame it took so long to actually arrive.


Which reveals the problem D has finding any relevant niche, as the community cannot decide into which direction to head into.

Java and C# also have acquired many capabilities that for 10 years were a plus from D over them.


This seems useful for code generation. Cannot relate this to any previous problems I encountered using c++

Any other interesting use of this?


My favorite use is putting user-defined attributes on data members, and using reflection to generate a UI to manipulate those values. I do it with these shadertoys:

https://github.com/seanbaxter/shaders#reflection-and-attribu...

Just mark your declarations up with custom attributes:

    [[.imgui::range_float {  .1,  5 }]] float Zoom = 1.5;
    [[.imgui::range_float {   0,  1 }]] float Speed = .15;
    [[.imgui::range_float {  .1,  1 }]] float XScale = .3;
    [[.imgui::range_float {   0, .5 }]] float YScale = .2;
Then loop over the members with a meta for, and emit widget code that's guided by the attribute kind and data. These attributes each define a scrollbar.

The kind of data you reflect over will likely come from within the program.


Nice! This is definitely my main usecase for reflecty things lately, along with serialization for the data (game engine scenarios). I've been doing static reflection + attributes through this: https://godbolt.org/z/enh8za4ja Which actually comes out to a not-so-bad syntax and the attributes can be read constexpr (some limitations though: simple aggregate-y structs, and all reflected fieds must appear before non-reflected ones).

Lately I've been working on a Go (pretty small subset -- no GC or concurrency) to C++ compiler and generating meta stuff as part of it. Mostly because I like how focused Go's syntax is and also it having an official parser and type checker in the standard library makes things pretty quick to get started.

I should play with Circle some time! It's definitely touching on a lot of the desired things from a metaprogramming layer.


In c++ there are some hacks that can start to help getting someswhere close (https://ossia.io/posts/reflection/) but this solution with attributes is what everyone dreams of


Seems that it could be used to solve an old-time classic: generate a mapping from an enum value to its string representation. Another use case that comes to my mind is maybe automating test case generation. Occasionally I was running into situations where I thought code generation could be useful, but not sure what could be a "killer app" equivalent for this feature.

Related topic: standardizing reflection in c++. https://youtu.be/ARxj3dfF_h0 https://en.cppreference.com/w/cpp/keyword/reflexpr


Enum to string is a one-line expression in Circle: https://godbolt.org/z/93f5o77zv

Circle has dozens of special traits for accessing useful stuff about types, packs, etc. Don't need to overengineer such a simple thing.



What’s wrong with an array


that would be great :-)


Imagine using this to build a balzingly fast serialization library that you’d use like protobufs. Or to explore lots of configurations of your code to search for the variant that runs fastest. Or to write a linear algebra library that doesn’t generate temporary values that are dynamically allocated.


Imagine you want to intern your printf strings somewhere so that your logs look like logit(“some message providing more details. %s, %d”, someStringArg, someIntArg). Typically you have to serialize the whole thing and store it. However, if you save the compile string into a separate database at compile time and the call site transforms to logit(msgId, someStringArg, someIntArg), then you’ve reduced your logging cost to the cost of serializing the log message which is drastically cheaper, faster and takes less space in whatever log storage system you use. You only pay the formatting cost when you go to display the logs to a person.


Why are the examples in C code rather idiomatic Modern C++?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: