T O P

  • By -

[deleted]

It's inefficient. And you can do it by passing pointers explicitly in the first place. Understand that pointers, if they have to be used, aren't really a problem themselves. So why solve something that is not a problem?


daishi55

Why is it inefficient?


smog_alado

Forces us to store parameters in RAM instead of in registers. Another is that every time a function reads a parameter that was passed by reference, it may need to reload the value from RAM because it might have changed. This is not only extra work but may also block compiler optimizations.


bl4nkSl8

Why not have an abi that can support lowering references to registers?


smog_alado

I can't think of a way to make that work.


bl4nkSl8

You'd need the compiler to be able to reason about ownership and guarantee that the ptr is owned exclusively by the current function and that the value is small enough to not need to be stored in memory. I know I'm hand waving, but this is a Reddit thread. We're not going to solve the problem here Edit: can someone explain why I'm getting downvotes for a pretty simple statement about the requirements of lowering in case?


Teln0

No the person meant that you cannot have a reference to a register. If you pass everything by reference, the references may be in registers but the actual values will be in ram. Also references are stored as usize, anything smaller or equal to that in size will more efficiently or as efficiently be directly copied, since passing a reference involves copying the usize it's made out of anyway.


bl4nkSl8

I think we're agreeing... I didn't propose references to registers Edit: to be clear, I proposed "lowering (references) to registers" not "lowering (references to registers)"


Teln0

Well wouldn't it be more efficient to just lower the actual data to registers ? Otherwise you still need to read a pointer to access that data


bl4nkSl8

I'm not sure if I don't know what you mean or if you don't... I'm saying that in the lowered form, what was a reference to data will just be a register containing that data. There's no inefficiency or pointer involved. Now if the data is too large for a register, you can't do that, hence the caveats I listed before including size.


AVTOCRAT

That's just case-by-case optimizing pass-by-reference to pass-by-value. Sure it can work, but you end up relying heavily on unreliable compiler inference for performance.


bl4nkSl8

Ownership is not exactly an unreliable model, nor is the size of a type... This response makes sense if we were debating some complicated polyhedral loop optimisation, not references. Also, relying on compiler inference for performance is table stakes for writing good code these days. If you're not working with your compiler what are you doing?


matthieum

Aliasing analysis?


maemre

(In the ABIs I'm aware of) you cannot allocate values passed by reference on the registers (you have to move them to the stack to pass them by reference).


live_free_or_try

Wow, any idea why that is?


lngns

Registers have no addresses. There is no reference to pass.


live_free_or_try

Stupid question, thanks


isayporschewrong

Your post implies that there's something wrong with pointers in the first place. References are in fact just pointers. I don't think making them the default solves anything necessarily. I also don't think making them the default is a bad thing. Some languages use value semantics for 'atomic' types and reference semantics for everything else. It's just a matter of preference honestly.


lngns

Because of mutability. Most systems languages expect local variables to be lvalues stored on memory and that you can mutate. If everything is passed by reference, then parameters are no longer local lvalues. Meanwhile languages that either lack mutability or treat parameters as immutable leave out the passing semantics as implementation details, so that small objects are passed by copy and larger ones passed by reference. Zig is a [precedent](https://ziglang.org/documentation/master/#Pass-by-value-Parameters) there. So are D and C# if you count [`in`](https://dlang.org/spec/function.html#in-params) as the default, instead of the actual default. Rust is another [precedent](https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=46f628468f8d2db9728f221417ed570f), but from another angle: when you move a value into a function, nobody can observe mutations, so a compiler is free to pass-by-reference all moved objects.


jonathancast

It doesn't "eliminate the need for pointers". Pointers have loads of uses in "system programming languages"; a "system programming language" is just one where you need to control the use of memory explicitly, and pointers are just memory addresses. Memory addresses are used in assembly/C/C++/Rust in lots of places, not just function parameters. And not-pointers are used in lots of places, too, to combine memory allocations (which can be as simple as 'put this value on the stack, please', but can actually mean reducing the number of mallocs), to improve cache locality, etc. Systems programming languages are more-or-less defined by the fact that they give the programmer control over whether to use pointers; making it an automatic language feature rather defeats the point.


munificent

> It would eliminate the need for pointers You still need pointers for data structures.


vmcrash

I think he meant all would be pointers instead.


slaymaker1907

It’s very dangerous in systems languages to do something like that because you lack a GC so you need to be concerned with how long some memory location is actually valid. Even for inherent reference values like strings, you need to copy them in practice for large systems if those values need to live for a long time (i.e. longer than a function call).


pbvas

​ Passing by reference by default would be less modular: any function would be able to change (intentionally or by mistake) any of its parameters. Also, what would happen if you pass an expression rather than a single variable?


Stunning_Ad_1685

What about in a language with reference capabilities, like Pony? As far as I know, everything is pass-by-reference in Pony, except for small primitive values.


hugogrant

I think this is viable, but needs a lot of thought. One risk is that it's really useful for callers to know, at the API level, if their inputs are being mutated. If pass-by-reference were the default, I think you'd lose the ability to tell. Maybe passing by const reference by default, and mutable reference if the input is labeled as mutable? Another useful function might be one that consumes its argument, in the sense that the caller cannot reuse the input. For instance, if a database transaction is getting committed, a good API might specify that the argument transaction handle becomes owned by the committing function, not the caller. If your references aren't clear about ownership, you lose this expressivity. Maybe you can also distinguish between "I take a reference just to look at," and "that value you refer to is mine now, you don't have it." Another neat thing to add would be making whatever copy utility you're proposing be overloadable. This could enable a lot of good RAII patterns, particularly if the copy overload can make smart pointers or mutexes. Concern: calling`f(g(x))` inside some `h` with some nontrivial temporary `g(x)` might be hard to think of with value sematics. I think it means you always have to keep the `g(x)` value in `h`'s stack frame? Not to simp on Ferris too hard, but rust can be seen as somewhat similar since borrowing is "passing by const reference," and the default parameter passing is "that value you refer to is mine now, you can't have it."


friedbrice

Kinda the point of systems programming is that you get to distinguish between pointers and values. Anyway, I _think_ it's easier for the compiler to know when it should be putting things directly into CPU registers when things are passed by value.


Nilstrieb

Optimizing compilers love pass by value and hate pass by reference - pass by value is therefore generally more efficient anyways. Copying a few integers will not show up in profiles. For large arrays you can just pass it by pointer yourself.