News for hackers. Stuff that matters.
Re:Nim Apocrypha, Vol. I by mhh__ on Wednesday December 23, 2020 @05:02AM (#25516136)
https://dlang.org/spec/statement.html#WithStatement

D also has withs. Definitely in the "not necessary but nice to have" category of features, particularly when implementing state machines (i.e. statment soup)

Re:Nim Apocrypha, Vol. I by mratsim on Wednesday December 23, 2020 @08:31AM (#25517435)
State machines can be metaprogrammed: https://github.com/mratsim/Synthesis

You describe the events, transitions and even interrupts and this compiles to optimized goto statements with no allocation, no indirect function calls, no switch statement.

There are compile-time checks to make sure you don't have state with no transition from and it also produce a visual graph of your state and transitions.

It's been tuned to be used as the core of my high performance multithreading runtime so zero overhead compared to handwritten.

It is suitable for any state machine with zero alloc constraint and state machines can be composed (they are just a function).

I hope in the future to be able to add model checking using Nim Z3 integration so that we can reach Ada/Sparks formal verification prowess: https://github.com/nim-lang/RFCs/issues/222

Re:Nim Apocrypha, Vol. I by mhh__ on Wednesday December 23, 2020 @09:06AM (#25517722)
I've seen people do similar things in D (although the "D way" of doing it would probably be to parse some kind of textual description and turn it into code at compile time). The cost/benefit of making a metaprogramming library just to write a lexer is fairly bad, however.

wrt to the SMT integration, it's something that I would very much like to try in D, but it's quite difficult to work out exactly where to start (and means bolting a fairly big dependency on the compiler). There also seems to be a big gap in the literature between "practical" verification done "in" the widget being verified (e.g. SystemVerilog code) and more academic work where, effectively, a parallel structure is built which represents the semantics of the widget.

Re:Nim Apocrypha, Vol. I by mratsim on Thursday December 24, 2020 @06:19AM (#25526600)
For a lexer/parser you should use a coroutine / suspendable function abstraction. Or a parser generator.
Re:Nim Apocrypha, Vol. I by planetis on Wednesday December 23, 2020 @05:21AM (#25516222)
We have like 5 different `with` macros including one in stdlib.
Re:Nim Apocrypha, Vol. I by mhh__ on Wednesday December 23, 2020 @06:53AM (#25516666)
I assume "We"=Nim?

It's an interesting pattern to test language designs with. On the one hand expressive macros can be disastrous in big codebases, on the other hand a more "monadic" (implemented via passing some kind of object through a chain rather than algebraically) way is very template-intensive.

Re:Nim Apocrypha, Vol. I by cb321 on Wednesday December 23, 2020 @07:23AM (#25516815)
At least one (very bottom of [1]) of the 5+ variants makes you list which fields the code gets access to (in a tiny 6 line Nim macro). That is an alternate, perhaps more keystroke-heavy solution to the problem bothering @simias.

[1] https://github.com/c-blake/cligen/blob/master/cligen/macUt.n...

Re:Nim Apocrypha, Vol. I by simias on Wednesday December 23, 2020 @07:10AM (#25516726)
I seem to be in the minority but I really dislike this type of sugar. I find that it always makes code harder to read because you can't disambiguate what the code is doing without some heavy context, and changes to the class can profoundly change the way the code is behaving without triggering as much as a warning.

For this same reason I really dislike that in C++ you can just implicitly drop the "this->" to target class members. You can never tell at a glance what "foo = blah" does if you don't know whether "foo" is a member of "this" or not.

I think your page demonstrates what I mean in the "nested WithStatement" example:

    Foo foo;
    Bar bar;
    Baz baz;

    f();               // prints "f"

    with(foo)
    {
        f();           // prints "Foo.f"

        with(bar)
        {
            f();       // prints "Bar.f"

            with(baz)
            {
                f();   // prints "Bar.f".  `Baz` does not implement `f()` so
                       // resolution is forwarded to `with(bar)`'s scope
            }
        }
        with(baz)
        {
            f();       // prints "Foo.f".  `Baz` does not implement `f()` so
                       // resolution is forwarded to `with(foo)`'s scope
        }
    }
    with(baz)
    {
        f();           // prints "f".  `Baz` does not implement `f()` so
                       // resolution is forwarded to `main`'s scope. `f()` is
                       // not implemented in `main`'s scope, so resolution is
                       // subsequently forward to module scope.
    }
Wi

I get that sometimes it can cut on a lot of repetition, but I think I would be fine if the syntax was more explicit while still avoiding repetition, for instance:

    with (some_object) {
        .some_member = 1;
        .some_other = 4;
        not_a_member = .some_method();
    }
And beyond that make it non nestable (i.e. only the first level of "with" is taken into account) to avoid the situation above with complicated overloading.

In my experience that would account for 99% of uses of `with` while making the code a lot more readable without requiring a lot of context to make sense of it.

Although frankly even that might arguably overkill, for dynamic languages or ones with type inference you might as well just do something like:

    {
        let v = &mut some_annoyingly.long.thing();

        v.foo = bar;
        v.baz();
    }
It's almost the same amount of typing and you don't need any magic.
Re:Nim Apocrypha, Vol. I by elcritch on Wednesday December 23, 2020 @03:43PM (#25521994)
The Nim `with` macro by @zevv doesn't modify functions or methods (that'd require explicit handling in the macro to do so and would be a nightmare to do correctly). Which means that example from D is not applicable to the Nim version at all.

My preference is Nim over D primarily since Nim compiles to C, but also overall the community appreciates syntax sugar but also has a decent sense as to when and how to use it. Most "sugar" in Nim needs to be explicitly imported. Literally `import sugar` is one of my first lines in many files.

    let v = &mut some_annoyingly.long.thing();
    v.foo = bar;
    v.baz();
In the example you list (is that Rust, or D?), if it was in C or Nim and those were structs-within-structs and not pointers/refs then `.thing` would be copied to a new `v` (if I recall the semantics correctly). So you'd end up with a weird "logic" bug where updates would disappear. The Nim `with` macro solves that by modifying the generated code,
Re:Nim Apocrypha, Vol. I by mhh__ on Wednesday December 23, 2020 @08:07AM (#25517202)
This is true however with is fairly uncommon, so as with any feature of languages that add syntax like this it's up to your judgement as to when to use it.
Re:Nim Apocrypha, Vol. I by TinkersW on Wednesday December 23, 2020 @08:11AM (#25517240)
Use syntax highlighting that differentiates between members and non members, problem solved.
Re:Nim Apocrypha, Vol. I by simias on Wednesday December 23, 2020 @10:17AM (#25518402)
That implies a very good "smart" highlighter that has in-depth knowledge of the language, something I don't like to rely upon because it's not always available and/or working properly.