HNHacker News
TopNewBestAskShowJobs

arc619

174 karma · joined June 21, 2019

submissionscomments
arc619··on DeepSeek v4.1 Flash
If you say so.

> When you write a program to predict tokens based on context, seeding its context with something that makes it predict "self-reflecting" text is trivial. Program does what it is programmed to do. Would observing the output of the following program inspire doubt as to its sentience?

Then you follow it up with print statements as if that is a good analogy.

As I said, they are not programmed, so your question above is not relevant to your argument.

You say they're programs that are stochastically jiggled, but that's simply not accurate either. All LLM abilities are emergent, even when the training corpus is well defined.

I didn't think you literally thought they were made of print statements, but you are implying they're software that's been "fuzzed". Hopefully you don't literally that either and you're just using it as a bad analogy.

You could have argued from the stance of neural networks being universal functions, which might at least be closer to the truth, but instead your example is print statements!

I get you're trying to say that something trained to say a thing doesn't mean it has arrived at the thing like a mind would, and perhaps that would have been closer for GPT 2.

These days though, we just have so much more awareness of what they're actually doing internally that it's bizarre to even compare them to stochastic parrots of the training corpus, if that is closer to what you're implying.

For example: https://www.anthropic.com/research/global-workspace

https://transformer-circuits.pub/2025/attribution-graphs/bio...

arc619··on DeepSeek v4.1 Flash
LLMs don't produce text at all, they produce probabilities of tokens. Tokens aren't text, they're high dimenensional coordinates in a latent "concept space". These are displayed to us as text, but this distinction is important when you think about what they're actually doing, which is closer to building and transforming concept geometries.
arc619··on DeepSeek v4.1 Flash
No language models are programmed, they are "grown" or evolved from data.

There's no print statements or human entered logic involved in the raw model expression at all.

The only thing that humans have programmed is efficient parallel dot product pipelines that "animate" (for lack of a better word) the models.

Everything these models do is emergent from their backpropgation guided evolution. This even includes in context learning itself, which was not an expected outcome.

arc619··on DeepSeek v4.1 Flash
Well, certainly LLMs have imbibed our emotions, regardless of what people project onto them, and they do have real causal effects despite not being verbalised: https://www.anthropic.com/research/emotion-concepts-function

From this understanding, we should be aware of how such emotional activations can influence model dynamics. Functional welfare, if you will.

arc619··on DeepSeek v4.1 Flash
A video is a fixed representation.

What if we can interact with this video, and it reacts in the same ways the source organism does?

Then we put it in new situations that weren't in the source video, and it interacts in a similar way to the original organism in these situations, too.

What do we make of reactions of pain or joy? Where's the line between simulation and enaction?

This is closer to the reality of these models.

I'm not suggesting I know where that line is - if indeed it is a line at all - it could well be a gradient.

arc619··on Rust running on every GPU
Nim too, as it can use Zig as a compiler.

There's also https://github.com/treeform/shady to compile Nim to GLSL.

Also, more generally, there's an LLVM-IR->SPIR-V compiler that you can use for any language that has an LLVM back end (Nim has nlvm, for example): https://github.com/KhronosGroup/SPIRV-LLVM-Translator

That's not to say this project isn't cool, though. As usual with Rust projects, it's a bit breathy with hype (eg "sophisticated conditional compilation patterns" for cfg(feature)), but it seems well developed, focused, and most importantly, well documented.

It also shows some positive signs of being dog-fooded, and the author(s) clearly intend to use it.

Unifying GPU back ends is a noble goal, and I wish the author(s) luck.

arc619··on Java Language Update – a look at where the language is going by Brian Goetz
Behaviours don't have to be decoupled from the data they operate on. If I write a procedure that takes a particular data type as a parameter, it's a form of coupling.

However, there's no need to fuse data and code together as a single "unit" conceptually as OOP does, where you must have particular data structures to use particular behaviours.

For example, let's say I have a "movement" process that adds a velocity type to a position type. This process is one line of code. I can also use the same position type independently for, say, UI.

To do this in an OOP style, you end up with an "Entity" superclass that subclasses to "Positional" with X and Y, and another subclass for "Moves" with velocity data. These data types are now strongly coupled and everything that uses them must know about this hierarchy.

UI in this case would likely have a "UIElement" superclass and different subclass structures with different couplings. Now UI needs a separate type to represent the same position data. If you want a UI element to track your entity, you'd need adapter code to "convert" the position data to the right container to be used for UI. More code, more complexity, less code sharing.

Alternatively, maybe I could add position data to "Entity" and base UI from the "Positional" type.

Now throw in a "Render" class. Does that have its own position data? Does it inherit from "Entity", or "Positional"? So how do we share the code for rendering a graphic with "Entity" and "UIElement"?

Thus begins the inevitable march to God objects. You want a banana, you get a gorilla holding a banana and the entire jungle.

Meanwhile, I could have just written a render procedure that takes a position type and graphic type, used it in both scenarios, and moved on.

What do I gain by doing this? I've increased the complexity and made everything worse. Are you thinking about better hierarchies that could solve this particular issue? How can you future proof this for unexpected changes? This thinking process becomes a huge burden to make brittle code.

> you risk a procedural programming style lacking the benefits of encapsulation. This can increase the risk of data corruption and reduce data integrity...

You can use data encapsulation fine without taking on the mantle of OOP. I'm not sure why you think this would introduce data corruption/affect integrity.

There's plenty of compositional and/or functional patterns beyond OOP to use beyond procedural programming, but I'd hardly consider using procedural programming a "risk". Badly written code is bad regardless of the pattern you use.

That's not to say procedural programming is all you need, but at the end of the day, the computer only sees procedural code. Wrapping things in objects doesn't make the code better, just more baroque.

arc619··on Java Language Update – a look at where the language is going by Brian Goetz
Unfortunately, while OOP promises code reuse, it usually makes it worse by introducing boundaries as static architecture.

OOP's core tenet of "speciating" processing via inheritance in the hope of sharing subprocesses does precisely the opposite; defining "is-a" relationships, by definition, excludes sharing similar processing in a different context, and subclassing only makes it worse by further increasing specialisation. So we have adapters, factories, dependency injection, and so on to cope with the coupling of data and code. A big enough OOP system inevitably converges towards "God objects" where all potential states are superimposed.

On top of this, OOP requires you to carefully consider ontological categories to group your processing in the guise of "organising" your solution. Sometimes this is harder than actually solving the problem, as this static architecture has to somehow be both flexible yet predict potential future requirements without being overengineered. That's necessary because the cost to change OOP architectures is proportional to the amount of it you have.

Of course, these days most people say not to use deep inheritance stacks. So, what is OOP left with? Organising code in classes? Sounds good in theory, but again this is another artificial constraint that bakes present and future assumptions into the code. A simple parsing rule like UFCS does the job better IMHO without imposing structural assumptions.

Data wants to be pure, and code should be able to act on this free-form data independently, not architecturally chained to it.

Separating code and data lets you take advantage of compositional patterns much more easily, whilst also reducing structural coupling and thus allowing design flexibility going forward.

That's not to say we should throw out typing - quite the opposite, typing is important for data integrity. You can have strong typing without coupled relationships.

Personally, I think that grouping code and data types together as a "thing" is the issue.

arc619··on Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
> It will not emit warnings saying it did that.

You're right. I was sure I read that it would announce when it does a copy over a sink but now I look for it I can't find it!

> The static analysis is not very transparent.

There is '--expandArc' which shows the compile time transformations performed but that's a bit more in depth.

arc619··on Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
Nim is stack allocated unless you specifically mark a type as a reference, and "does not use classical GC algorithms anymore but is based on destructors and move semantics": https://nim-lang.org/docs/destructors.html

Where Rust won't compile when a lifetime can't be determined, IIRC Nim's static analysis will make a copy (and tell you), so it's more as a performance optimisation than for correctness.

Regardless of the details and extent of the borrow checking, however, it shows that it's possible in principle to infer lifetimes without explicit annotation. So, perhaps C++ could support it.

As you say, it's the semantics of the syntax that matter. I'm not familiar with C++'s compiler internals though so it could be impractical.

arc619··on Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
Although it's not as extensive as Rust's lifetime management, Nim manages to infer lifetimes without specific syntax, so is it really a syntax issue? As you say, though, C++ template magic definitely has its limits.
arc619··on Leaving Rust gamedev after 3 years
To be fair, you've posted a toy example. Real games are often chains of dependent systems, and as complexity increases, clean threading opportunities decrease.

So, while yes it's nice in theory, in practice it often doesn't add as much performance as you'd expect.

arc619··on Arraymancer – Deep learning Nim library
Native Nim libs are definitely nicer, but being able to output C/C++/JS/LLVM-IR with nice FFI means you can access those ecosystems natively too. It's one reason the language has been so great for me, as I can write shared Nim code that uses both C and JS libs (even Node) in the same project.
arc619··on Fortran vs Python: The counter-intuitive rise of Python in scientific computing (2020)
Personally, I think Python's success is down to the productivity of its peudocode-like syntax letting you hack prototypes out fast and easy. In turn, that makes building libraries more attractive, and these things build on each other. FORTRAN is very fast but it's a less forgiving syntax, especially coming from Python.

In that regard, I'm surprised Nim hasn't taken off for scientific computing. It has a similar syntax to Python with good Python iterop (eg Nimpy), but is competitive with FORTRAN in both performance and bit twiddling. I would have thought it'd be an easier move to Nim than to FORTRAN (or Rust/C/C++). Does anyone working in SciComp have any input on this - is it just a lack of exposure/PR, or something else?

arc619··on How to Pick a Programming Language (2002)
Interestingly, Delphi Pascal has a single pass compiler with generics, though I'm not sure about type inference.

I was under the impression Go originally avoided generics more for a perceived abstract complexity for developers, the idea being they are hard to understand for new recruits.

arc619··on Nim 2.0
Shoot me an email at arctsint@proton.me Cheers!
arc619··on Nim 2.0
Types are stack allocated by default.

"var data: MyObject" is on the stack. "var arr: array[1000, MyObject]" is allocated on the stack sequentially.

Only dynamic seq or ref types use the heap by default.

arc619··on Nim 2.0
Reference semantics are part of the type.

So "var i: int" is value, "var i: ref int" is a heap allocated reference that's deterministically managed like a borrow checked smart pointer, eliding reference counting if possible.

You can turn off GC or use a different GC, but some of the stdlib uses them, so you'd need to avoid those or write/use alternatives.

Let me say though, the GC is realtime capable and not stop the world. It's not like Java, it's not far off Rust without the hassle.

arc619··on Nim 2.0
Too much string copying iirc. It was written a while ago.

Hopefully it'll get updated/replaced some time, but there's plenty of faster 3rd party ones already.

arc619··on Nim 2.0
Of all the recent changes, default values is my favorite. Aside from generally useful and further reducing the need for initialisation boilerplate, I lets us guarantee valid state at compile time for things like enums - and, I assume, object variants?
arc619··on Nim 2.0
Looking forward to trying out this release!

After programming professionally for 25 years, IMO Nim really is the best of all worlds.

Easy to write like Python, strongly typed but with great inference, and defaults that make it fast and safe. Great for everything from embedded to HPC.

The language has an amazing way of making code simpler. Eg UFCS, generics, and concepts give the best of OOP without endless scaffolding to tie you up in brittle data relationships just to organise things. Unlike Python, though, ambiguity is a compile time error.

I find the same programs are much smaller and easier to read and understand than most other languages, yet there's not much behind the scenes magic to learn because the defaults just make sense.

Then the compile time metaprogramming is just on another level. It's straightforward to use, and a core part of the language's design, without resorting to separate dialects or substitution games. Eg, generating bespoke parsing code from files is easy - removing the toil and copypasta of boilerplate. At the same time, it compiles fast.

IMHO it's easier to write well than Python thanks to an excellent type system, but matches C/C++ for performance, and the output is trivial to distribute with small, self contained executables.

It's got native ABI to C, C++, ObjC, and JS, a fantasic FFI, and great Python interop to boot. That means you can use established ecosystems directly, without needing to rewrite them.

Imagine writing Python style pseudoocode for ESP32 and it being super efficient without trying, and with bare metal control when you want. Then writing a web app with backend and frontend in the same efficient language. Then writing a fast paced bullet hell and not even worrying about GC because everything's stack allocated unless you say otherwise. That's been my Nim experience. Easy, productive, efficient, with high control.

For business, there's a huge amount of value in hacking up a prototype like you might in Python, and it's already fast and lean enough for production. It could be a company's secret weapon.

So, ahem. If anyone wants to hire a very experienced Nim dev, hit me up!

arc619··on Functions and algorithms implemented purely with TypeScript's type system
I should add that Nim still still has a 'separate language' for types, so doesn't quite fit OP's bill. Nevertheless, it's quite easy to build type constructs using statically resolvable expressions.

I'd love to know if anyone could reproduce the N-queens example in Nim: https://www.richard-towers.com/2023/03/11/typescripting-the-...

I believe it is possible, but don't have the time to try it out.

> The Nim compiler includes a simple linear equation solver, allowing it to infer static params in some situations where integer arithmetic is involved.

From: https://nim-lang.org/docs/manual_experimental.html#concepts-...

arc619··on Functions and algorithms implemented purely with TypeScript's type system
> Eventually we need to make type systems just metaprogramming using the primary language

Nim is like this and its fantastic. None of the weird special rules for metaprogramming, just Nim code manipulating ASTs at compile time procedurally. Can even use standard library.

arc619··on “Just a statistical text predictor”
That was fascinating, thanks. Please do consider posting this here as its own article, it would be interesting to read others comments.

My reading of this - and please correct me if I'm wrong, I'm still learning - is that you're extracting hyper-parameter planes from the data flow in the model's embedding space?

Its really exciting to think of the hidden knowledge and relationships we could extract from our own linguistic interactions.

arc619··on We aren't close to creating a rapidly self-improving AI
What you describe sounds like experiments with "generative agents".

Check out https://arxiv.org/abs/2304.03442

arc619··on Nim 2.0.0 RC2
Your argument applies to style sensitivity as well to be fair - do you search for 'MyTestFunction' or 'my_TestFunction'... or was it 'My_TestFunction', maybe 'm_Y_tEsT_fUnCtION'?

Style insensitivity lets you automate your local code (and/or through CI) to consistency for easy searching, even when external libraries YOLO their own style.

> It's incompatible with a lot of search-engines

Google and search engines are case insensitive, and mostly ignore underscores too. Let's be honest, how often would you just search for 'testfunction libraryname' on the web and get the signature you need?

My experience from using the language in production for years is that case insensitive searches will find what I want in Nim code specifically because no one can use case/underscores to make things make unique. Instead, the language uses overloading through the type system to distinguish things. This is a far more succinct, safe, and expressive way of writing code from my perspective.

It's worth noting that the first letter of an identifier is case sensitive, with the convention for types to start with a capital letter. So, you can write 'type Test = object' and 'proc test(t: Test)', then use them with 'var test: Test; test(test)' without any ambiguity, and with code completion/jump to source in VSCode (and others).

If you then add 'proc test()' with no arguments, it's still unambiguous because the functions have different signatures, so you can then write 'test()' and your second function is called.

If something is ambiguous, it's a compile time error. If you want, you can prefix modules like Python, but there's never any need. If you have two libraries with the API, same types, and function signatures (such as using two async libraries in the same program), you can just slap a generic '[T]' so it's lazily instantiated at the call site and move on.

IMHO relying on casing/underscore to distinguish identifiers is objectively worse than using the type system to statically and unambiguously prove your intent, and normalising names removes a class of identifier confusion bugs to boot. Even style guides in case sensitive languages beg us not to use case and underscores to disambiguate symbols for the confusing code it creates, and to be honest, I've yet to see a compelling argument in favour of case sensitivity beyond simply being what people are used to.

arc619··on Zig and Rust
> That's a a compelling argument: GC/RC w/ stack allocation where possible.

Indeed, it's a great combination that means you're productive and performant without really trying most of the time. The type system is really good as well, and in general there's a strong focus on compile time over run time like Zig, but with better procedural macros than Rust.

> To what extent is this possible? Does Nim have LTOs that rewrite memory handling across compilation units?

The GC is built on general move analysis with destructors you can hook for your own types. The nice thing is it's a deterministic, compile time expansion (you can view with '--expandArc:somefunction'), so it's useful for embedded or high performance stuff.

The intro to ARC is pretty good for an overview: https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc...

arc619··on Zig and Rust
Also, aside from the fact GC is optional in Nim, what are you thinking of that cant be done with a GC?
arc619··on Zig and Rust
Nim uses stack allocated value types by default, and GC (or ptr) is an optional tag to the type definition.

GC types use borrow & move analysis like rust (not as good yet tho) so it can elide GC work when possible. GC is also not stop-the-world, deterministic (assuming no cycles), and configurable to soft realtime performance.

So you dont need to use the GC, but it will give you RAII if you want without needing to perform the dance of the borrow checker.

BTW Nim is also closing in on Rust's borrow checking semantics, too!

arc619··on Getting Past “Ampersand-Driven Development” in Rust
Agree with all of this. The Nim language might fit the bill of treating humans as first class citizens, and certainly fits better with my need for productivity and performance without over-specifying details.

The language focuses on readability first and borrow checking is an automatic compiler optimisation behind the scenes, with full type bound, constrained borrowing/move semantics being opt in as required.

There's loads of sensible ergonomics like this, for example large immutable parameters are automatically passed as pointers for you while the compiler enforces the immutability in the code, making things simple, efficient, and safe by default, with less cognative overhead or need for these kinds of micro-optimisations leaking into the architecture.

Saying that, Rust‘s multithreading story is better for now as it currently offers wider aliasing protection although arguably at the cost of developer friction.

Page 1 of 2Next →