Implementing argument ownership on my own function

I want my function to take ownership of the arguments, like how String constructor takes ownership of the UInt8[] array:

julia> mybytes = UInt8.([125, 119, 48, 126, 40]);

julia> mystring = String(mybytes)
"}w0~("

julia> mybytes
0-element Array{UInt8,1}

This is what I want from my function:

julia> sock = MySocket(1,2)
julia> fn_that_takes_ownership(sock)
julia> sock
nothing

How do I implement that fn_that_takes_ownership function?

this can’t be done for two reasons:

  1. The String(::Vector{UInt8}) is a special case:
String(v::Vector{UInt8}) = ccall(:jl_array_to_string, Ref{String}, (Any,), v)
  1. conceptually, you can at least mimic the first case by calling empty!() yourself (after copying out the data), but in order to change sock to nothing, you actually need to evaluate something like sock = nothing, which can’t be done by a function, only by a macro
1 Like

Before going into code - please keep in mind that the String constructor empties the UInt8 collection - and your mybytes variable does not get assigned to another type.

Regarding your use-case, you seem to want to reassign the global scope sock name to the nothing value.

Now, an example that is closer to how String constructor consumes the UInt8 collection might imply putting your MySocket object in some kind of wrapper/container: and, in your constructor you make sure you empty the container.

This might be something close to what you are looking for:

struct MySocket
    a::Int
    b::Int
end

struct SocketUser
    sock::MySocket
    function SocketUser(sock::Base.RefValue{Union{Nothing,MySocket}})
        s = sock[]
        isnothing(s) && error("Cannot use an empty container")
        sock[] = nothing
        new(s)
    end
end

sock = Ref{Union{Nothing,MySocket}}(MySocket(1, 2))

# this constructor will `consume` the `sock` content
SocketUser(sock) # SocketUser(MySocket(1, 2))

# true
isnothing(sock[])