HNHacker News
TopNewBestAskShowJobs

arc619

174 karma · joined June 21, 2019

submissionscomments
arc619··on High-order Virtual Machine (HVM): Massively parallel, optimal functional runtime
TBF the reply in that link was written 4 years ago, before the language went 1.0

> Nim lacks official support to multiple inheritance or interfaces

Multiple inheritance is a bit of a trainwreck IMO (see diamond problem).

The language isn't designed around OOP, and is instead procedural with metaprogramming for extension. You get more bang for your buck this way, but for people with their head in inheritance it’s probably a shock.

arc619··on /r/antiwork: A tragedy of sanewashing and social gentrification
UBI is added on top of work so work will always mean you're better off.

Would you give up your job just to spend all day doing nothing, or would you end up doing something productive?

If you had infinite money, would you do nothing?

What do uber rich people do all day? Why do they work?

arc619··on Nim vs Rust Benchmarks
With noting that the GC in Nim (not "stop the world" BTW) is attached to the type. Unless you declare a type as `ref`, you're using stack allocation.

Even if you do use the GC, the compiler elides GC work if the type doesn't escape the scope.

arc619··on Nim vs Rust Benchmarks
...both Rust and C have runtimes: https://blog.mgattozzi.dev/rusts-runtime/
arc619··on Why static languages suffer from complexity
They're probably laughing because a) you're suggesting manually doing the work static typing does in a dynamic language because its untenable not to for large projects, and b) you can't easily add type hints to other people's libraries.
arc619··on Why static languages suffer from complexity
In other words, in Python you have to rely on your colleagues manually writing documentation, and if they don't you're out of luck and they're 'bad developers' and potentially the whole product is affected.

In static languages this simply isn't a problem. Types are checked for consistency at compile time and you don't have to rely on people toiling on this busy work.

Not to say documentation isn't necessary, or good, but isn't something you need to create working programs because otherwise no one knows wtf any variable is without running the program.

arc619··on Why static languages suffer from complexity
This entire article can be summarised as "compile time stuff should use the same language as run time".

I guess the author just hasn't encountered Nim before, where anything becomes compile time by just assigning to a const, and macros have access to the real AST without substitution. Macros also allow compile time type inspection, as they are a first class citizen rather than tacked on.

The compile time print, AFAICT, already exists in Nim as the `&` macro in strformat. That lets you interpolate what you like at compile time, and supports run time values too.

arc619··on Effortless personal productivity (or how I learned to love my monkey mind)
I do what you described too. I think of it as neural degaussing.
arc619··on Expectations for generics in Go 1.18
> the downside is there is significant compile time and link time cost to generics.

Are we talking statistically significant or productivity significant compile time cost? Go has a fairly fast compiler, it would be a shame if generics made that a less stand-out feature.

arc619··on Faster Python with Guido van Rossum
I've never used Qt myself, but the Status messaging app written in Nim does, so it's definitely doable: https://github.com/status-im/status-desktop

There's also a QML wrapper here: https://github.com/filcuc/nimqml

arc619··on Faster Python with Guido van Rossum
Oops wrong link for nimporter. Actual link: https://github.com/Pebaz/Nimporter
arc619··on Faster Python with Guido van Rossum
Nim can use Python's ecosystem in both directions with nimpy https://github.com/yglukhov/nimpy and nimporter https://github.com/yglukhov/nimpy

This lets you gradually transition hot path Python modules to Nim, get compiled performance generally on par with C and Rust, whilst enjoying strong, static typing with great type inference.

In my experience (6-7 years 4 of which are full time) Nim strikes the perfect balance of the productivity you get with Python with high performance at the same time.

Also the metaprogramming features are incredible and, importantly, don't use a language subset but use the base Nim language itself.

arc619··on Am I stuck in a local maximum?
You only need to map the database types to the language types at worst. So int, string, timestamps, binary, maybe GUID. Or you could just use string for all data and then you're pretty much matching a dynamic language.

Results from joins between arbitrary queries are just lists of these types per field.

arc619··on Open 3D Engine
> just have things called “entities” which own things called “components” - are hard to work with, almost by definition (ie you have to be very explicit about data layout and dependencies).

My experience has been completely the opposite to this. In fact being explicit about data layout and dependencies is a hallmark of a OOP rather than ECS.

In compiled languages the dependencies in object hierarchies are fixed at compile time and can only support tree designs, so you have to plan ahead for all possible combinations to even build relationships with OOP, even with composition (because its static).

With ECS everything is decoupled so you can write a system that does X and it affects nothing else.

This leaves you free to design by isolated processes rather than by code structure, and entities naturally do whatever processes their data supports dynamically.

Makes iterating designs incredibly rapid and offers design options that are convoluted and fragile with OOP such as completely changing what an entity does at run time.

For instance you can move the keyboard input component from a player entity to a monster or even something as random as a building and it just works - you didn't have to design for it, you don't even need to change any code. Remove the health component, now the entity is invincible, remove the gravity component and now it can fly, add a homing component and now it seeks a target. All this is trivial and can be done at run time. Want flying flaming lampposts the player can control? Just combine the appropriate components. Need to drastically pivot the design? Vastly less work than OOP - sometimes just a case of changing the data in components or their combination in entities without touching systems. Don't need this flexibility? Still gives you a more modular and less coupled design.

As a nice bonus this flexibility comes with more cache friendly performance than static hierarchies to boot.

arc619··on An intro to Zig's integer casting for C programmers
Nim is built like this. The gc is opt-in by type and manual memory management is simple. All other types are stack allocated by default.

The new gc is pretty much compiler assisted scope managed smart pointers as well. Also when using the gc you can build your own types with custom create/free/copy/move operators to do what you want without worrying about a stop the world gc.

Using the arc gc pretty much compiles down to what you'd do manually. For cycles you can use the orc gc, again it's all opt in.

I find this a great balance of productivity and performance, where it's easy to have high control when you want it, and still get good performance when you're not bothered.

arc619··on Std::visit is everything wrong with modern C++ (2017)
Not yet, no. I hope with companies like JetBrains working on their Nim plugin https://plugins.jetbrains.com/plugin/15128-nim we'll see more focus put on a smooth IDE based debugging experience in particular.
arc619··on Std::visit is everything wrong with modern C++ (2017)
Yes, if the target is C++ then the whole output will be in C++, including code for GC operations, so you can directly inspect how this is translated. You can actually choose between several GCs for different needs: https://nim-lang.org/docs/gc.html

It's worth mentioning that by default all types in Nim are stack allocated, and you have full manual memory management to the same level as C/C++ but with better type safety and less boilerplate. The GC is only used when you tag a type as `ref`, in strings, and the 'vector' dynamic list type, `seq`.

The newer GC, ARC (not related to Swift's ARC), is similar to RAII - scope based, non-atomic, deterministic, shares memory between threads but not stop-the-world, and uses move semantics: https://nim-lang.org/docs/destructors.html

This makes the GC a nice to use addition for resource management but not a fundamental requirement or speed limitation.

In my experience the default (thread-local refc + cycle collection) GC is very performant already, but it's straightforward to write code that works entirely on the stack, or create objects that wrap manual heap allocs, or use custom external memory allocators. Passing `--gc:none` removes the GC entirely from the compilation target, for example if you're working with very constrained embedded devices with the caveat that less of the stdlib is available (currently).

The ARC GC (doesn't handle cycles unlike it's sibling ORC) is aiming to be lean enough to be used in hard realtime and memory constrained embedded systems. For hard realtime though I'd expect most people would just manually manage their types anyway on the heap or stack.

If you're doing interop between Nim and C++ and want Nim's GC to manage types that you're passing directly to pure C++ code, you can tell the GC that the data is still being used with GC_Ref() or not with GC_Unref(). There are a few libraries for C/C++ interop, such as: https://github.com/nimterop/nimterop

Personally in this case I would probably just manually allocate memory memory in Nim or C++ and not use GC'd types across boundaries for clarity if nothing else, still it's an option if your design requires it.

Finally, there is a tool to help auto-translate C/C++ to Nim with the c2nim tool: https://github.com/nim-lang/c2nim and docs: https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst

arc619··on Std::visit is everything wrong with modern C++ (2017)
Technically yes, but directives are inserted so GDB reports the line number, source code, and parameters of the Nim file.

However GDB shows the name mangling suffix in generated code, and types are their native types. There's a script called nim-gdb to add pretty printers for types to the GDB output to show the Nim source types.

Perhaps surprisingly though, the C and C++ generated output itself is fairly straightforward, even with name mangling suffixes. The inserted directives tell you the Nim source line so you can navigate it fairly well if you want to, and the suffix means the variable is unique referenced in the code. As far as I know you can use any debugger that supports the target language, though I've not tried anything but GDB myself.

It's very rare for me to dig into the generated code but sometimes I'm curious about the data structure analog in the target language. In the case of Nim's object variants, last time I looked when compiling to C they were ultimately reduced to simple checked union types.

arc619··on Std::visit is everything wrong with modern C++ (2017)
In VSCode and Neovim there's a visual debugger but in general you can compile with `--debugger:native` and use GDB, for example:

A guide to debugging and profiling: https://nim-lang.org/blog/2017/10/02/documenting-profiling-a...

Guide for working directly with GDB-Nim: https://internet-of-tomohiro.netlify.app/nim/gdb.en.html

A walk through and extra info with the language devs: https://www.youtube.com/watch?v=DmYOPkI_LzU

arc619··on Std::visit is everything wrong with modern C++ (2017)
Another option is to gradually replace parts of the C++ with Nim code set to output to C++. As such you get the advantages of a high level, low friction language with fast compile times and move semantics, ABI compatibility with C++, and a really nice FFI. You can import or export functions and so on between the languages, use any C++ libraries in Nim (or visa versa), and even directly emit C++ from Nim if required.

Gradually porting like this lets you keep using your code base whilst introducing new or overly complex stuff in a language that's faster and easier to write (usually ends up with less than half the LoC of the equivalent C++ but often way, way less than that). Metaprogramming is also very nice, easier to reason about and perhaps most importantly, even with lots of macros doesn't noticeably affect the fast compiles.

Another advantage is once you have some Nim code you can choose to change the target to C or ObjC (or even JS or LLVM) so you're actually increasing portability.

This all depends on how you rank 'maturity' of course. Nim's been around for longer than Rust and Go IIRC, and it's been rock solid for me but you may have different parameters. It certainly helps being able to directly use libraries for C and C++ if you can't find an appropriate Nim implementation.

Edit: For contrast, consider the challenges in the article for variants in C++, then the equivilent object variants in Nim:

    type
      MyVarKind = enum mvkNumber, mvkString
      MyVariant = object
        case kind: MyVarKind
        of mvkNumber:
          num: int
        of mvkString:
          str: string

    var myVariant = MyVariant(kind: mvkNumber)
    myVariant.num = 1
    myVariant.str = "Oops"  # Error: 'str' is not accessible using discriminant 'kind' of type 'MyVariant'
arc619··on Nim compiler — Pascal source code
> No algebraic datatypes

Not sure what you mean there, there's product types with tuples and objects, and sum types as object variants.

> Pattern matching

Eh, I mean it's just sugar over a case statement.

  let
    num = 5
    str = case num
      of 1: "One!"
      of 2, 3, 5, 7, 11: "This is a prime"
      of 13..19: "A teen"
      else: "Unknown"  # Compile error if all cases arent covered.
As you say there's libraries that let you deconstruct and partially match more complex types if you need that. Being able to create things like pattern matching, async, and novel multithreading runtimes as a library in Nim shows how powerful (and useful) the metaprogramming is.

Enums in Rust are more interesting, but again nothing you can't do with an object variant.

arc619··on Nim compiler — Pascal source code
Why not just use Nim? The language is rapidly converging on an ownership model similar to rust anyway and has better metaprogramming, more compile targets and a high development velocity (plus faster compile times).

Rust has a bigger ecosystem of course, but Nim's is pretty decent and you can use C, C++ and JS libs natively for anything else.

arc619··on Prologue: Full-Stack Web Framework Written in Nim
What is the perceived penalty of unqualified imports in Nim specifically? The only one that seems valid is you can't immediately see the module a proc is defined in, but you can opt in as you say with module qualifiers if you want to.

None of the "namespace pollution" stuff applies to Nim since ambiguity is a compile time error and there's no performance penalty for having everything imported as Nim uses dead path elimination.

arc619··on Prologue: Full-Stack Web Framework Written in Nim
The tl;dr is that Nim is statically typed so two functions that take different types are not ambiguous. If there is something that takes the same parameters, of the same type, in the same order it wont compile and you would use the module prefix to disambiguate.

In over 5 years of coding in Nim this came up once when two libraries defined a `Point` type. They were subsequently given distinct names so i didnt even need it for long.

Other options for ambiguous calls are renaming things during import with `import thing as othername` or using `type SdlPoint = sdl2.point` and so on, but i have never needed to do this.

The main point is that its a compile time error to try to call an ambiguous thing. Btw mouse over in VSCode shows you where a symbol is defined too.

arc619··on How to manage HTML DOM with vanilla JavaScript only?
I agree with the central thrust of what you're saying here; its definitely easier now than it has ever been, and things are now moving towards the simplicity of how it used to be when creating desktop apps using web tech with the advantage that they're cross platform.

However this improvement is in spite of using a tool designed for a different medium, rather than because of it, and the years and abstractions its taken to get here express this.

Having said that, cross platform is better going from web to desktop than the other way round.

arc619··on How to manage HTML DOM with vanilla JavaScript only?
>If frontend was bicycle science then I must have missed that in my 10+yrs writing frontends with JS+CSS.

What you've said directly proves OPs point - you've missed the central message: UIs used to be bicycle science before everyone started using JS to make them.

They mentioned VB as in visual basic. GUIs with VB/Delphi are a case of dragging controls to where you want, pixel perfect every time on every desktop.

Web technologies are not designed for desktops but for building on top of HTML, so everything is an abstraction to get back to something that used to be possible with zero experience and sometimes even zero programming. For example, a simple notepad clone can be made in Delphi without a single line of code.

Now you need to 'full stack' to even know what's going on under all the layers just to place a control at an x,y and even then it can't be guaranteed because of all the different browsers, css edge cases, and other caveats.

arc619··on Information Is Physics
I think the article's overall stride is not so much about how these things are represented in neuronal mapping per se, and more that we shouldn't apply the idea of computer mechanics to organisms.

Less load/process/store of absolute data and more like natural processes such as the process of erosion creating rivers. The analogy of the environment as a "lock" and organisms are just the most fit "keys" to success in particular environment.

So the computer analogy is bad because organisms are more a matrix of interactions, feedbacks and responses that work well enough, but dont follow a "logical" design. This can be replicated within a computer easily and the result is evolutionary computation & hardware, genetic algorithms and evolutionary neural networks. The problem in understanding the result of evolutionary systems is that they're blind to design and only respond to fitness and therefore create systems that are so tightly coupled it's a quest to understand how the model even works.

So the article is suggesting we shouldn't apply human design principles to evolved solutions. Perhaps we need some kind of "messy science" to make sense of it all.

Going forward, machine learning running evolutionary algorithms on neural networks should be able to produce sufficiently incomprehensibility for us to be studying our own inventions for years to come.

← PreviousPage 2 of 2