If Odin Had Macros

(gingerbill.org)

33 points | by mattwilsonn888 4 days ago ago

22 comments

  • Imustaskforhelp 6 hours ago

    > The road to hell is not paved with good intentions but rather the lack of intention.

    Although I am a man who seemingly seems to love the idea of a freedom of a language like nim,julia,lisp,(scala?) etc., just langauges which can give you a lot of freedom in general, my intention has always been: I have been asking for freedom irl, what is wrong with giving developers freedom in programming languages.

    I can still respect this opinion and I followed up on pragmatic choice and I mean, its Mr's Wilson's language and honestly the freedom to have a language like this might be freedom in it of itself too and I can respect his opinions and I might check odin again later too.

    https://skytrias.itch.io/todool I saw it from Odin lang page a long time back ago and I actually really loved this tool/ am thinking of creating an open source alternative in an another language like golang/kotlin/typescript/nim (i like to imagine things and be lazy sometimes lol) but there are definitely a lot of projects like jangafx which are written in odin iirc which are definitely really impressive

    I will also think about this statement more as I do think that the reason why I sometimes lack intention is because I want to define good first, I don't want to take my opinions and run with it if they hurt people directly or indirectly and I am willing to have lack of opinions first to really understand the situation I suppose but I can respect his opinion in this thing too. Something worth thinking about for me. So thanks!

    • randomstringxyz 6 hours ago

      All of those languages have a lot of freedom, you just ("just") need to reach into the FFI to do it. Lua, which is the only one I have used extensively, is the most literal definition of scripting. It's designed to be written in conjunction with C. Even languages like Haskell with a gigantic runtime still expect you to put in some C for hot paths.

      • Imustaskforhelp 6 hours ago

        FFI scares me if I am being honest and that is why I always try to think of a language which can do a lot of things themselves without having to reach for FFI thinking its going to be my last resort most of the time.

        So that was my perspective when I had written up my comment.

        What are some really good languages for FFI? Lua as you suggest?

        I have always had this notion that FFI is really hard and so firstly I would like to ask if that's really true and secondly is there a langauge which can make it easy to work with FFI the most? Like do you suggest lua for something?

        • tsuru an hour ago

          FFI is harder if the target lib doesn't have a C interface.

          I feel I'm forced to reach for FFI if I want to do anything graphical e.g Wayland or OpenGL. Otherwise it's optional

        • PinkMilkshake 4 hours ago

          PUC Lua is supposedly a bit of a pain for ffi, but I havent tried it myself. Luajit is some kind of crazy magic. You can (almost) just copy and paste the c header file into the ffi.cdef function and then start using c functions as if they were lua functions.

  • ecshafer 3 hours ago

    I really like Odin as a language. I have tried Rust and Zig as well (of the newer systems languages). I think that Odin has a great niche and a lot of potential in the games industry. If what you need is a systems language with good speed and manual memory management and memory safety, BUT you also need fast DEVELOPMENT speed its great. Rust slows down development speed too much, especially for something like games where you are playing things loose and need to pivot a lot. Zig is also fantastic, but I think that some of the extra safety features make it a bit slower in development speed.

  • leecommamichael an hour ago

    I’ve been writing only Odin for about 6 months now and I love it. The grammar is dead-simple, and I’ve successfully intuited how dozens of features work and compose together. My GUI app goes from compiling to painting a frame in under a second. How cool is that?

  • whobre 4 hours ago

    One of the things I like about Odin is the features it doesn't have. Package manager is the big one, but OOP constructs and macros are not far behind. Good job!

  • bbkane 3 hours ago

    Does anyone have good examples of the "metaprograms (programs that make/analyse a program" he's referring to?

    Making these types of programs relatively easy in Go (with stdlib ways to manipulate source code) has been a huge boon to the ecosystem (golangci-lint linters, code gen tools).

    I'd love to see examples of what that looks like in Odin

    • spartanatreyu 3 hours ago

      > Does anyone have good examples of the "metaprograms (programs that make/analyse a program" he's referring to?

      That's a little tricky because almost anything can be a metaprogram. They're basically used when something could be "simplified" by writing a DSL, but you don't want to invent a whole new language (but you're going to anyway).

      But some examples off the top of my head:

      - For HTTP routers: HTTP methods (GET/POST/PATCH/DELETE/QUERY) are used when requesting a route. Instead of setting up the boilerplate of registering a url route and handling the different possible http method calls, a developer might want to use a more ergonomic macro to handle all the setup. (e.g. @<HTTP method>(<string of url>, <lamda function that returns a string that is sent back to the browser>)

      - For MVC Frameworks (Same thing for MVVM, MVCL, MV*, etc... frameworks): Making a Model, View and Controller Macro that takes a name and a function and hooks it up to the application.

      - For standards implementations: Adding special/non-standard bounds checking that is only calculated during compile time and removed from runtime for performance purposes (e.g. This int can only be between the ranges of -12 <-> 378 and 10621 <-> 11012)

      - For game design: This level can only be solved by following the specified sequence. During the compile/build step, a proofer is run that ensures that the conditions for solving the level still hold. That way if someone adds a teleport item later in development, it doesn't break earlier levels.

      - For testing: To mark a test case for a function

  • valorzard 7 hours ago

    Something I don’t get.

    Odin doesn’t support closures (a la C++ or Rust)

    The thing is, I don’t understand why.

    Odin’s FAQ says it’s because closures require automatic memory management. [0] But if that’s the case, why do languages like C++ and Ada [1] support closures?

    [0] https://odin-lang.org/docs/faq/#does-odin-have-closures

    [1] https://learn.adacore.com/courses/advanced-ada/parts/resourc...

    • wk_end 6 hours ago

      I can't speak for Ada, but C++ closures require that you explicitly specify what's captured from the enclosing environment and how (i.e. copy or reference). That capture is also unsafe, which relates to the issue of automatic memory management: for instance, if you have a function that returns a closure that's captured a reference to something in the function's stack frame, stack semantics mean that value will be destroyed. I'm sure C++ developers are fine with them but - having not used them in anger - they sound quite brittle.

      The answer in the Odin FAQ maybe could be expanded to say "many uses of closures require automatic memory management, and while Odin could add some kind of support for closures to handle the uses that don't, it'd add too much complexity and too much potential for bugs to be worthwhile". Not to speak for gingerbill, here.

    • doug-moen 6 hours ago

      what ginger bill actually said was

      > I’d argue that actual closures which are unified everywhere as a single procedure type with non-capturing procedure values require some form of automatic-memory-management. That does not necessarily garbage collection nor ARC, but it could be something akin to RAII. This is all still automatic and against the philosophy of Odin.

      C++ doesn't have this feature either. A C++ closure does not have the same type as a regular C-style function with the same argument types and result type. The types of functions and closures are not unified.

      And C++ does have RAII, which the author feels is a kind of automatic memory management and against the philosophy of Odin.

      So C++ doesn't have the feature G.B. says is impossible. I don't know enough to comment on Ada.

      • tialaramex 4 hours ago

        What Bill wrote, on his own web site, about his own language is simply this:

        > For closures to work correctly would require a form of automatic memory management which will never be implemented into Odin.

        I suppose you can insist Bill thinks "correctly" means all that verbiage about unified types - but then a reasonable question would be why doesn't Odin provide these "not correct" closures people enjoy in other languages ?

        RAII is entirely irrelevant, the disposal of a closure over a Goose is the same as disposal of a Goose value itself. In practice I expect a language like Odin would prefer to close over references, but again Odin is able to dispose of references so what's the problem?

    • kibwen 5 hours ago

      Rust shows that closures don't require automatic memory management, unless you consider Rust's static ownership analysis to be "automatic memory management", which I suppose you could, but it's all at compile-time, not runtime. Of course, it's fair if he doesn't want his language to have an ownership system, but ownership systems honestly aren't very complex, they're just different.

      • bbkane 3 hours ago

        You really don't think ownership systems are that complex kibwen?

        I just watched a recent Polonius talk ( https://m.youtube.com/watch?v=uCN_LRcswts ) and came away very impressed with the difficulty of implementing (or even modeling) the borrow checker. Or maybe you're referring to something else?

        • kibwen 2 hours ago

          Ownership and the borrow checker two distinct things; putting these concepts together is the premier novelty of Rust. "Ownership" is this: an analysis pass that enforces single-ownership of values (call it "affine types" if you want to be fancy, but it's an extremely simple analysis), along with a mechanism to allow types to opt-out of single-ownership and allow multiple ownership/implicit copying (what Rust calls the `Copy` trait). That's all it is, and it automatically gives you Rust's trick of "automatic static memory management". It's much simpler than a borrow checker, which would also require a notion of generics and subtyping, to say nothing of lifetimes (or a control flow graph, which is what you want if you want a good borrow checker). Such a system of ownership without a borrow checker could even be memory-safe, if your language doesn't allow unmanaged pointers (though it wouldn't be as efficient as Rust, and would involve more copying, and makes for slightly more annoying APIs).

    • csb6 6 hours ago

      Automatic memory management isn’t necessary for closures, but if you don’t have it then it is easy to have dangling pointers (e.g. you capture a local variable by reference, return the closure object, and then call the closure and use the referenced variable). This is a problem in C++ but isn’t in Ada due to Ada’s stricter scoping rules. Capturing variables by value is safe (assuming the captured values contain no dangling references themselves). It might require allocation if there were type-erased function objects (like std::function in C++), but this could be done using explicit allocator and deallocator functions with some help from the compiler to determine the closure object’s size.

    • randomstringxyz 6 hours ago

      Conceptually, think about it. Coroutines require copying not only the variables but the function itself, outside of the lifetime of the parent function. (Or at least pointers thereto.) I would like to hear about a language with static coroutines but I am not aware of any. Even Rust doesn't do it, they just make you pass the lifetime around.

      • kibwen 5 hours ago

        The parent is talking about closures, not coroutines. Rust does have closures that don't require a GC or passing lifetimes around (there's not even any syntax for putting a lifetime on a closure).

        • thayne an hour ago

          Rust closures can have lifetimes, and the lifetime of a closure is restricted to the lifetime of the shortest lived reference that it captures. But that just means the compiler protects you from having dangling pointers in your closure. And I don't think you can get much better than that without a runtime garbage collector.