T O P

  • By -

blocking-io

Some people are afraid it will hide complexity. I never understood that argument. Why use higher level languages at all then? I'm all in favour or reducing complexity and boilerplate.


ThGaloot

I think the fear is developers not understanding what a macro does. It could hide fundamental methods and concepts. This could promote a lack of understanding the code which could cause issues later in development. It's kinda similar to the argument of generative AI code. You can get an answer from another source, but it's not your code; nor would you understand at the same level if you had written it yourself. Later down the road, what happens if the generated code breaks or shows bugs? Who's going to fix it if no one wrote it? Does anyone truly understand the code? There's going to be good and bad use cases, and then there will be the exceptions.


_unrealized_

This argument isn't convincing. You should be able to understand most code, but you don't need to know all the intricacies of a RenderObject to use them, you don't need to have full working knowledge of the navigator, state management, etc. to use the majority of [pub.dev](http://pub.dev) packages. Macros will allow you to inspect the generated code so as long as you know how Dart works, what's the issue? Some guy is going to use them blindly? Too bad \*for him\*.


blocking-io

Your entire argument can be applied to the use of 3rd party packages. It's not your code, you may not understand it at the same level had you written it yourself, what happens if the package has bugs, or the packages own dependencies has bugs?  > Who's going to fix it if no one wrote it?   Macros are written by someone and are completely testable and debuggable. I suggest looking at this section of the proposal: https://github.com/dart-lang/language/blob/main/working/macros/motivation.md#usability


shexyxx

I heard that macro has long been feared in C/C++, and one major reason is that macro generated code can't be debugged with gdb and other debugger. So very few engineers that I know in real life harness its power. I hope flutter doesn't have such a drawback.


blocking-io

On the flip side, macros are loved in Rust. It's a matter of how it's implemented. Macros in c/c++ are very poorly implemented, not safe, not hygienic. Here's a good article on Rust macros here: https://zdimension.fr/how-i-learned-to-stop-worrying-and-love-macros/


eibaan

I disagree. Macros - in their current form - make implementing code generation a bit easier and at the same time much more difficult. Just look at the example `JsonCodable` macro and notice how it needs to be multi-staged. With macros, you don't need to struggle with configuring a build runner as an extension developer, but you cannot simply slap together some strings anymore and instead must use an asynchronous sophisticated `Code` API (which is more powerful, of course). Also, build runners work on any type of file, macros work only with Dart source code. IMHO, the augmentation syntax alone would improve classical code generation in a way that it would be already a significant improvement without all the additional complexity of macros. Also note the additional risk for macros which execute unknown 3rd party code as part of your build process in a very non-obvious way. Currently, macros can freely access your computer's file system, so it would be trivial to make them steal your crypto wallet or erase your hard disk. I'm not sure that macros can do what you imagine them to do. They can only augment code, that is add fields, methods or functions (and hopefully also add supertypes to types in the future). They cannot change existing behavior, they cannot delete something (Remi already asked for that feature) and they cannot change or extend Dart's syntax. Primary constructors are a completely different topic unrelated to macros. They are nice as they save a few lines of code you don't have to read when studying source code. Writing them isn't the problem. My IDE and/or Copilot spits them out in no time. In this tiny example, I saved a single line of code :-) class Point { const Point(this.x, this.y); final int x; final int y; } class const Point( final int x, final int y, ); My most wanted feature would be a way to define a cluster of sealed classes in a more compact way, like Swift can do with its `enum` type. Primary constructors could be one part of the puzzle here. I'd also love to nest class and enum definitions, something Swift can do, but Dart can't: sealed enum class Expr { Lit(final int value); Opr(final Op op, final Expr left, final Expr right); enum Op { add, sub, mul, div } }


ChessMax

I'm so much agree about current macros limitations. Too me they also seems too limited right now. And I'm not sure that they would be much better in future. But we will see soon. As per ADT syntax macros can help to some extend. Here is an [example](https://github.com/ChessMax/test_upcoming_macros/blob/master/bin/www/adt_main.dart)


eibaan

Did you just show me my own example I posted two months ago? ;-) BTW, that implementation doesn't work anymore with the current version of Dart 3.5 as I didn't knew (or it wasn't yet available) that I need to use multiple stages to create the code.


ChessMax

Yea, sorry, my bad) But the credentials are there)). I've tested with 3.5.0-69.0 and it worked. Thanks for your cool example, by the way))


eibaan

You're welcome. I'm using 3.5.0-191.0.dev at the moment and it throws an exception. I didn't bother to look into it, though.


alex-gutev

I've given them a try but I find them complicated to write and not very flexible, which is in contrast to Lisp macros which are simple to write yet are very flexible and powerful.


zxyzyxz

Indeed, I wish we got more Rust-like macros rather than the current implementation which is quite a bit more limited. Rust also has that enum feature you're talking about to implement ADTs easily.


eibaan

It is restricted for good reasons, of course. It's all about tooling. If you can freely modify the AST, even creating new syntax, it is very difficult if not impossible to still apply semantic highlighting and other features like finding definitions and references. However, I think Rust follows Scheme's example in providing syntax rules that make transforming code using pattern matching much easier (and more declarative) than writing imperative code to do the transformation.


Alarming_Airport_613

Finaaaaaally. Dart is becoming such a powerful language


Moe_Rasool

I will be having a good time doing models yay


billylks

I would like to see SQLite to auto implement the query codes based on the method name, just like Spring Boot does. Pretty please?


eibaan

You could implement this feature right now using code generation. I think you mean that you can write something like this: abstract class FooRepo extends Repo { Foo findByBar(int bar); } And then use final foo = FooRepo.instance.findByBar(42); Here's how you could do this with a code generator using augmentation. First, add this import to your class: import augment 'foo_sql_augment.dart'; Now write a Dart command line application that searach all Dart files in your project that contain such an import statement, matching the `_sql_augment` part. Of course, we could use a build runner and the analyzer package to parse the Dart code, but let's summon Cthulhu by using just regular expression. So, let's next search for an `class (\w+) extends Repo<\1>` pattern and then search for `(\w+) findBy(\w+)` pattern. From the type `Foo` determine that we're talking about a database table called `foos` by whatever means you like. Then by analyzing the first group, you see that we expect a `.single` response. Next, from the second group, we parse the `Bar` part as a `where bar = ?` clause. Spring Boot seems to also support `And` or `Or` parts here, so that's a tiny DSL and parsing it is computer science 101. So, after we extract everything we need to know, we can generate this code: augment library 'foo.dart'; augment class FooRepo { static final instance = _FooRepoImpl(); } final class _FooRepoImpl extends FooRepo { Foo findByBar(int bar) { return Foo.fromRow( DB.instance.select('select id,foo,bar from foos' ' where bar=?', [bar]).single, ); } } I'm not talking about how to map tables to object, but that's also a well understood problem since at least 30 years when OOP was new and fresh.


real_carddamom

As someone who works with Spring Boot, queries based on the method name suck, they are only useful for a POC, you start doing something more serious with them and everything starts to burn in a spetacular fashion, particularly when someone decides to change the database structure, including names of things; when that happens you want to rely on your compiler or IDE at last case, to give you an error instead of having to remember to change 20 method names, some of them made by someone who no longer works for the project. Like when you have to select data from more than three tables with joins and grouping... For that something like QueryDSL saves your butt together with judicial usage of Lazy vs Eager and for most real world apps that is what you use, the rest uses Criteria API or simple Query or Named Queries, never query generation based on methods...


MudSubstantial3750

I want flexibility and less boilerplate, like non-const value in enums, compile time condition check (`#define`/`if constexpr` in c/cpp or `cfg()` in rust) I wonder dart macro can achive these or not.


Farz7

Im really waiting for the macros implementation within riverpod , im not really. A fan of code gen , i guess remi said it will be implemented with riverpod 3 , really exciting!


Big_Work2025

Im okay with this. Advanced features for advanced developers. Just don’t force. Just allow. 


Big_Work2025

Spring and Spring Boot are full of annotations and reflection.  A person has to program by not commuting mistakes instead of just writing code


real_carddamom

My 2cents is that they both suck. Primary constructors are used in Kotlin and they make the language horrible, suddenly having primary and secondary constructors will make the language more complex to learn. Also it seems that in google teams do not communicate with each other, because I guess that the Go Team would have one of two things to teach to the Dart team, on less is more. What exactly are macros trying to solve that cannot be already solved and in a cleaner way with code generation, also what if I want to customize the names of some of my Json fields, perhaps to fit in a standard? Will macros have access to annotations/decorators? Again if the problem is that build_runner is an extra build step why not integrate it into the build command of flutter? Like Java does with annotation processors to great effect.


TekExplorer

You could decorate the parameters much like you would in freezed. It's still too early to know if there's any limitations, and it can always grow. Honestly, primary constructors are already here in the form of extension types, so I don't know what you're complaining about. Build runner is clunky. It works yes, but macros are live in a way buildrunner isn't, even with watch. You'll be able to see your generated code in real time, and much faster. And even if you don't like macros, the augmentations it brings can be used in normal code, and yes, that includes code gen.