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
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[])