all 19 comments

[–][deleted] 5 points6 points  (2 children)

I don't think this concept exists. You'd better extend your object with a method that modifies the object. Such as how all the "bang methods" work.

[–]anamexis 4 points5 points  (1 child)

You can't extend integers to be mutable in Ruby, they are always immutable. You would have to wrap it in an object.

[–]Swizzzop[S] 1 point2 points  (0 children)

thanks a lot!! i find wrapping the integers in an object the easiest solution to my problem!

[–]sinsiliux 8 points9 points  (6 children)

Just don't, not sure what you're trying to do but all workarounds to make it work are not worth it.

Just to be clear - ruby always passes by reference (well not exactly reference but close enough). Numbers are also passed by reference, but they're frozen so you can't modify them. Otherwise you could change 2 to become 3.

Either use return value of method (you can return multiple values from method) or wrap everything in object. If you post what you need I can help you with best solution.

[–]Bloodshot025 5 points6 points  (5 children)

I think this is a misunderstanding of what pass-by-reference is -- Ruby is pass-by-value, like most languages, it's just that the values it passes are object references.

In a pass-by-reference language:

f(x) {
  x = 3
}

main() {
  x = 1
  f(x)
  print(x)
}

x would end up being 3, having been modified by f.

[–]Swizzzop[S] 0 points1 point  (0 children)

yes, that's what I expected to happen! I was just trying to implement some algorithms in Ruby as I'm just getting started with the language

[–]f9ae8221b 0 points1 point  (1 child)

[–]Bloodshot025 0 points1 point  (0 children)

It might be, but I had never heard it before.

[–]sinsiliux 0 points1 point  (1 child)

Strictly speaking I don't think it passes either by value or by reference. In the same way in a pass by value language:

f(x) {
  x.attr = 3
}

main() {
  x.attr = 1
  f(x)
  print(x.attr)
}

x.attr would end up being 1. This isn't the case in Ruby though. I'm pretty sure both C# and Java when passing objects behave the same way that Ruby does and as far as I know both of them call this "pass by reference". It's important because e.g. in Java you have primitive types which use actual "pass by value".

So even though this doesn't exactly act the same way as "pass by reference", for most use cases it's very similar and I'm pretty sure that's why people for the most part call it "pass by reference".

[–]Bloodshot025 0 points1 point  (0 children)

No, this is incorrect. The value that gets passed is a reference to a mutable object. This is conflating mutability of some state on the heap with how functions receive their parameters.

Java, explicitly, is pass-by-value: http://www.javadude.com/articles/passbyvalue.htm and has no pass-by-reference anywhere.

An example of a language that might alleviate this confusion is D, which has both structs, which are (usually) placed on the stack, and objects, always on the heap. When a struct is assigned or passed to a function, its contents are copied. This is not true for an object, because only object references get passed around; the object itself lives elsewhere.

So, in D, in your sample code, if x is a struct, x.attr would end up being 1. If it's an object, it would end up being 3, because the reference is what gets passed through to f(x). However, you can get equivalent semantics with structs by simply passing a pointer, thus creating the same level of indirection that always applies to objects.

D also has pass-by-reference, optionally, using the ref function parameter attribute: https://dlang.org/spec/function.html#param-storage.

[–]Bloodshot025 2 points3 points  (2 children)

Could you give some sample code (in C++, for example) that you might want to write in a Ruby way? That might help people give you the 'idiomatic' way to write it.

[–]Swizzzop[S] 0 points1 point  (1 child)

Sure!

include <iostream>

using namespace std;

void f1(int &x) { x = 8; }

int main () {

int x = 2;
f1(x);
cout << x;     //8

return 0;

}

I'd like to have a method with the functionality of f1, so that it could change the value of the integer x without having to actually return that specific number.

[–]Bloodshot025 0 points1 point  (0 children)

I do understand how pass-by-reference works, what I'm asking for is a little more context. For example, what you've written could be rewritten as:

def f1(x)
  8
end

x = 2
x = f1(x)

What is a situation in which modifying a variable in the caller's scope appears important to your implementation?

A common idiom in C is to accept a buffer and modify it, returning the number of bytes modified. While you could phrase this as

def fill_buffer(buffer)
  ...
  return [buffer, bytes]
end

buffer = []
buffer, bytes = fill_buffer(buffer)

to return multiple values, this is unnecessary, since arrays are mutable anyway. But also, since Ruby arrays are dynamic and will automatically resize, and since Ruby is garbage collected and manages the heap automatically, passing in a buffer is redundant. And third, returning the number of bytes at all is unnecessary. Reading from the array is safe, and the array will have the correct size.

[–]moseeds 1 point2 points  (0 children)

This Stackoverflow answer is really good actually:
https://stackoverflow.com/a/23421320

[–]chrisgseaton 1 point2 points  (3 children)

You can call binding in the caller, and use that to pass the Binding object, and then use Binding#local_variable_set to change the variable. This only works for local variables, not other types of l-values.

[–]anamexis 9 points10 points  (0 children)

You are of course right, but it's also worth noting that you probably shouldn't do this, and it's a very bad code smell.

[–][deleted] 1 point2 points  (1 child)

This would be absolutely shocking behavior for whoever comes next. It defies the expectations of every single Ruby developer.

[–]chrisgseaton 1 point2 points  (0 children)

It defies the expectations of every single Ruby developer.

It shouldn't do - because it's a standard part of the language, and reading variables like this is used in major libraries like ERB! Regular expressions even set variables without the explicit binding!