#unable to pass by value

27 messages · Page 1 of 1 (latest)

desert schooner
#

i noticed i'm unable to pass variables by value, even primitives ,such as Int , are either borrowed or mutable refs "inout" or moved "owned"

torpid bone
#

@desert schooner why do you think Int is not being passed by value? I suspect it is, but not sure how to actually check.

Also see the @register_passable decorator which you can use to make your own structs register- passable, which is a kind of accelerated pass by value.

The thing about Mojo is it's promoting the idea of "value semantics" which is very different than Python's reference semantics.

I keep returning to this section of the manual and it's pretty good:
https://docs.modular.com/mojo/programming-manual.html#argument-passing-control-and-memory-ownership

A tour of major Mojo language features with code examples.

desert schooner
kind relic
#

In the same way, you can pass copies to functions that take owned arguments

#

notice that this will compile:

fn main():
    let x: Int = 1
    let y: Int = x
    print(x)
#

had int been restricted to move only semantics you would have to write this:

fn main():
    let x: Int = 1
    let y: Int = x^ # passing ownership here
    print(x)
#

and it would not compile, as it would be an attempt to use x after move

forest dust
#

yeah value semantics has another name: copy semantics

#

lol

kind relic
#

You can easily verify it with this example:

struct MoveOnlyInt:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value
    
    fn __moveinit__(inout self, owned previous: Self):
        self.value = previous.value

fn main():
    let x: MoveOnlyInt = 1
    let y = x
    print(x.value)
#

this does not compile

#

if you correct it by adding the ^ operator after x you will get this error:

./test.mojo:14:12: error: use of uninitialized value 'x'
    print(x.value)
           ^
./test.mojo:12:5: note: 'x' declared here
    let x: MoveOnlyInt = 1
    ^
mojo: error: failed to run the pass manager
#

a "move" is still a copy (sometimes). This is just semantics to allow you to protect objects that have some internal state, like a file descriptor - without shared mutable state reference semantics lead to

#

So a copyable type, a "value" is still safe to use where owned is required as it's inherently less restrictive than a move-only type.
I think it's clear to see why this would not be safe in the other direction

#

I hope this makes the difference a bit clearer.

#

note that this is just semantics, the compiler can do whatever optimisations it wants as long as it's safe, so you can't make assumptions about how these things are actually passed around.

torpid bone
#

yeah it says value-semantics in the docs but then i created a def function with an Int argument and when i hover over it with the cursor the function signature says owned Int which means it just transfers ownership rather than copy it

@kind relic I wonder if it's possible the LSP/tooltips disagrees vs what the compiler is actually doing?

Docs say (note that def and fn work differently):

A Mojo def function receives a copy of all arguments—it can modify arguments inside the function, but the changes are not visible outside the function.

Anyways, interesting question! If you think it's not actually a copy, that seems like at least a docs bug.

kind relic
#

I can’t say anything about the tooltips because they’re broken for me, I don’t see any

But I think I heard of cases where the lsp disagreed

#

If you copy it makes sense it would be owned, is it different for an fn?

desert schooner
#

@kind relic @torpid bone perhaps you guys have misunderstood me . consider the code below

fn main():
    var x = 10
    copy(x)
    print(x)


fn copy( x: Int):
  x +=1

the compiler complains if you try to modify x inside the copy function because its not mutable, right??. The only way to provide mutability is with the inout keyword, but inout automatically makes x a mutable reference, which means modifying it also modifies the the original variable.

my point is that primitive types like int should copy by default or atleast allow the programmer to decide if they want a mutable reference or a mutable copied value

kind relic
#

Oh, okay
You want a mutable parameter that isn't a reference

#

There is a reason why it's probably not in mojo

#

in Swift, in the very beginning you could have both inout and var parameters

#

apparently that was confusing so var was removed in one of the earliest proposals

kind relic