Live data from Hacker News

Show HN: A small programming language where everything is pass-by-value

github.com

31–40 of 64 posts

Re: Show HN: A small programming language where everything is pass-by-value

#31
post #29

Earlier quoted context omitted.

It's only semantically a pass-by-value, in reality a reference is passed and the data is only copied if needed (i.e. value is mutated while shared).

So the language has reference semantics , and (per the edit) for every object (like in Python)? (Ah, no, your example elsewhere in the thread suggests that the referred-to structures get implicitly copied all over the place.)

Nope, it's value semantics (unlike Python), the references are just an internal optimization. Implicit copies happen when a list/dict with more than one reference is mutated.

Re: Show HN: A small programming language where everything is pass-by-value

#32

At the risk of telling you what you already know and/or did not mean to say: not everything can be a value. If everything is a value then no computation (reduction) is possible. Why? Because computation stops at values. This is traditional programming language/lambda calculus nomenclature and dogma. See Plotkin's classic work on PCF (~ 1975) for instance; Winskel's semantics text (~ 1990) is more approachable. Things…

IMHO this is both unnecessarily pedantic and not really quite right. Let’s say we accept the premise that “everything is a value” means reduction is impossible. But a value is just the result of reducing a term until it is irreducible (a normal form). So if there is no reduction there can’t really be values either—there is just “prose” (syntax) and you might as well read a book.

Re: Show HN: A small programming language where everything is pass-by-value

#33
post #28

The threading story here is what grabbed my attention. Pass-by-value with copy-on-write means you get data-race immunity without any locks or channels. You just pass data to a thread and mutations stay local. That's a genuinely useful property. I've worked on systems where we spent more time reasoning about shared state than writing actual logic. The typical answer is "just make everything immutable" but then you los…

Why exactly is imperative syntax "convenient" specifically in the context of inter-thread communication?

He's likely referencing that you would need to use different syntax and style, like re-assigning a variable or chaining calls, like when working with a String in Java.

In C, you can simply mutate the underlying characters. So changing the fifth character in a string is as easy as:

    str[4] = 0;
Whereas using the immutable syntax you might have to do something like:

   str = str.substr(0, 4) + "\0" + str.substr(4);

Re: Show HN: A small programming language where everything is pass-by-value

#34

Earlier quoted context omitted.

Not everything in C is pass-by-value. Sure, you can argue that a pointer itself is passed by value, but the data it points to is definitely not.

cool project. can you take the address of a variable in some way? i.e. implement your own pointers if its really really needed?

> can you take the address of a variable in some way?

I intentionally didn't add this, mostly because I wanted to explore how far you can get without it (and keep the language simple). Having a "real" pointer as a first class type wouldn't work though, since it would break a lot of the assumptions I use for optimizations.

I did think about two different versions of this but didn't end up adding either:

- Something like `inout` parameters in Swift, which aren't first class pointers. This is really just an alternate syntax for returning multiple values. - A "ref" type, which is essentially a mutable container for an arbitrary value. Passing the container around would share a reference to the same mutable value. This still wouldn't allow modifying values "outside" of the container though.

Re: Show HN: A small programming language where everything is pass-by-value

#35

The threading story here is what grabbed my attention. Pass-by-value with copy-on-write means you get data-race immunity without any locks or channels. You just pass data to a thread and mutations stay local. That's a genuinely useful property. I've worked on systems where we spent more time reasoning about shared state than writing actual logic. The typical answer is "just make everything immutable" but then you los…

> Have you benchmarked any real workloads? Nothing "real", just the synthetic benchmarks in the ./benchmarks dir. Unnecessary copies are definitely a risk, and there's certain code patterns that are much harder for my interpreter to detect and remove. E.g. the nbodies has lots of modifications to dicts stored in arrays, and is also the only benchmark that loses to Python. The other big performance limitation with my…

There is some prior work on mitigating the performance cost of immutability that you might be interested in. For example, Clojure's persistent vectors allow fast modifications without destroying the original vector, because internally they're wide trees rather than just linear arrays of memory. This allows for assignments to be implemented without a copy of the full vector. https://hypirion.com/musings/understanding-persistent-vector...

Re: Show HN: A small programming language where everything is pass-by-value

#36
post #28

Earlier quoted context omitted.

Why exactly is imperative syntax "convenient" specifically in the context of inter-thread communication?

He's likely referencing that you would need to use different syntax and style, like re-assigning a variable or chaining calls, like when working with a String in Java. In C, you can simply mutate the underlying characters. So changing the fifth character in a string is as easy as: str[4] = 0; Whereas using the immutable syntax you might have to do something like: str = str.substr(0, 4) + "\0" + str.substr(4);

Well, yes, that's how it becomes convenient in general. But why would you be doing things like that when communicating between threads?

Re: Show HN: A small programming language where everything is pass-by-value

#37
post #29

Earlier quoted context omitted.

So the language has reference semantics , and (per the edit) for every object (like in Python)? (Ah, no, your example elsewhere in the thread suggests that the referred-to structures get implicitly copied all over the place.)

Nope, it's value semantics (unlike Python), the references are just an internal optimization. Implicit copies happen when a list/dict with more than one reference is mutated.

> the references are just an internal optimization

Optimization specifically for function calls, or... ?

Because if you're doing all this copy-on-write anyway, the indirection seems to be a needless cost in other contexts.

Re: Show HN: A small programming language where everything is pass-by-value

#38
Nim has a similar, strong preference for value semantics. However, its dynamic heap types (strings, seqs, tables) are all implemented as wrappers that hide the internal references and behave with value semantics by default, unless explicitly escape hatched. It makes it incredibly easy to manipulate almost any data in a functional, expression-oriented manner, while preserving the speed and efficiency of being backed by a doubling array-list.

Re: Show HN: A small programming language where everything is pass-by-value

#39
post #6

At the risk of telling you what you already know and/or did not mean to say: not everything can be a value. If everything is a value then no computation (reduction) is possible. Why? Because computation stops at values. This is traditional programming language/lambda calculus nomenclature and dogma. See Plotkin's classic work on PCF (~ 1975) for instance; Winskel's semantics text (~ 1990) is more approachable. Things…

Thanks, some interesting reading there that I will check out (I wasn't aware of PCF). Perhaps I should've used more precise wording: "All types are value types". > Standard ML [...] It has all you dream of and more The main thing here that's missing in Standard ML (and most other functional languages) is the "mutable" part of "mutable value semantics" - i.e., the ability to modify variables in-place (even nested part…

Quick note then a more wordy response (and after being dinged in another thread yesterday, the tl;dr is your usage is correct, ignore purposely avoiding context criticism of wording):

SML has mutation, but only for Ref Cells, which humorously are values themselves. Not that’s what you’re really talking about here.

Now for the wordy part…

As another of your sibling commenters said GP was being incredibly pedantic. While his reference to Plotkin/Winskel and the PCF thread of research is formative, it is of particular note for Structural Operational Semantics.

The real issue GP is raising that in programming language semantics there are two distinct ways in which the term ‘value’ is used. Worse still is that the terms are not just distinct but are broadly from two very distinct fields in PLT. So, what are the two uses:

  1) when the domain of discourse is Operational Semantics of Programming Languages, a ‘value’ is a term in the formal abstract syntax of the language which is not subject to reduction via any other transition defined over the syntax;

  2) when the domain of discourse is the Evaluation and Default Kinds of arguments passed to functions and the semantic implications of those defaults, a ‘value’ is defined in the negative as those semantic objects which ARE NOT references [1];
which from the definitions alone, it is clear your designation of your language as ‘pass-by-value’ is a distinct thing from GP’s usage of the term.

While GP’s usage of ‘value’ is in line with a long standing tradition, that tradition is firmly within the academic/functional programming language syntax and semantics sphere. Your usage, as is PLAINLY APPARENT from context, is absolutely correct and in line with long standing usage within discussion (and academic work) on imperative (and otherwise non-functional) programming language semantics. So keep phrasing discussions about Herd using the ‘pass-by-value’ and ‘everything is a value’. It’s not only contextually correct and historically justified, it is utterly within the ‘vernacular’ of normal programming language discussions.

One last thought, your language’s adoption of totally defaulting to passing arguments (to functions, threads, basically any control construct), with copy-on-write being an optimization only, should make implementing a non-reified linearity qualifier on types relatively simple to implement, that would address some of the locking anti-optimizations and address some of your static analysis that you mentioned where not working 100%.

———————

1: Reference here include Rust/C++ style lightly abstracted references, nearly zero abstraction pointers, and then the references as discussed when talking about Python, Ruby, JavaScript, C++ smart pointers, Rust’s higher level abstractions over references, etc which are a very abstract concept of reference.

Post reply on HN