Regarding C++, I would argue that MLIR is roughly as accessible from other languages as LLVM. That is, if you want just to run passes or construct pieces of IR using already-defined constructs, adding the bindings is trivial. However, if you want to add new concepts into the IR, you should do it in the language that the IR is defined in. Most of MLIR operations are actually generated from Tablegen definitions, there's not that much hand-written C++ for that. We can also provide bindings to inspect the IR from different languages, at which point you can envision calling back from C++ to the another language to implement passes. The risk is to end up with the "JSON of compiler IRs" as we call it, where an operation has a string id, a string kind, a list of strings of operation ids producing its operands and so on to a full stringly typed system.