Are there Rust variable naming conventions for things like Option<T>? - variables

Is there a convention for variable naming in cases like the following? I find myself having to have two names, one the optional and one for the unwrapped.
let user = match optional_user {
Some(u) => {
u
}
None => {
new("guest", "guest").unwrap()
}
};

I'm unsure if there is a convention per say, but I often see (and use) maybe for Options. i.e.
let maybe_thing: Option<Thing> = ...
let thing: Thing = ...
Also, in regards to your use of u and user in this situation, it is fine to use user in both places. i.e.
let user = match maybe_user {
Some(user) => user,
...
This is because the match expression will be evaluated prior to the let assignment.
However (slightly off topic) #Manishearth is correct, in this case it would be nicer to use or_else. i.e.
let user = maybe_user.or_else(|| new("guest", "guest")).unwrap();
I'd recommend becoming familiar with the rest of Option's methods too as they are excellent for reducing match boilerplate.

If you're going to use a variable to initialize another and you don't need to use the first variable anymore, you can use the same name for both variables.
let user = /* something that returns Option<?> */;
let user = match user {
Some(u) => {
u
}
None => {
new("guest", "guest").unwrap()
}
};
In the initializer for the second let binding, the identifier user resolves to the first user variable, rather than the one being defined, because that one is not initialized yet. Variables defined in a let statement only enter the scope after the whole let statement. The second user variable shadows the first user variable for the rest of the block, though.
You can also use this trick to turn a mutable variable into an immutable variable:
let mut m = HashMap::new();
/* fill m */
let m = m; // freeze m
Here, the second let doesn't have the mut keyword, so m is no longer mutable. Since it's also shadowing m, you no longer have mutable access to m (though you can still add a let mut later on to make it mutable again).

Firstly, your match block can be replaced by optional_user.or_else(|| new("guest", "guest")).unwrap()
Usually for destructures where the destructured variable isn't used in a large block, a short name like u is common. However it would be better to call it user if the block was larger with many statements.

Related

Can I serialize a closure to Vec<u8> then deserialize and execute it?

I want to do something like this pseudocode:
let mut vec = Vec<u8>::new();
vec.resize(1024); // Some large-enough size
serialize(&vec, || { .... });
// ... other code blah blah ...
deserialize(&vec); // This will execute the closure
Ideally, I would be able to run deserialize in another thread, which is the whole point of doing this really.
I do not want to send an opcode and data because this way opens up a remarkably clean programming model where you don't create messages and send them. Instead you just run arbitrarily complex code in another thread.
Why "remarkably clean"?
There are no opcodes (messages) that need to be created. i.e., less code.
There is no switch statement for opcode dispatch on the receiving end. i.e., less code.
Since there is no protocol, there is no need to version the messages. i.e., less code.
This idea cannot be used across processes, but that's OK for my needs.
Without using unsafe? No. No no no.
The problem is that since Vec<u8>s can be trivially modified, you can easily violate Rust's safety invariants. Consider the following code:
let vec = Vec<u8>::new();
vec.resize(1024);
// Our theoretical serialize function.
serialize(&vec, || { /* ... */ });
vec[0] = 0x90; // What happens to the closure now?
deserialize(&vec); // There goes any memory safety...
However, if all you want to do is send closures between threads, consider using something like std::sync::mpsc, which supports sending closures:
use std::thread;
use std::sync::mpsc::channel;
let (tx, rx) = channel();
thread::spawn(move || {
tx.send(|| { "hi" }).unwrap();
});
let f = rx.recv().unwrap();
assert_eq!(f(), "hi");
My guess, however, is that this is not actually what you want to do. Like Netwave said in the comments, you most likely actually want to send the data and a tag of the operation; for example:
// On one thread...
tx.send((Op::REMOVE_FILE, path));
// and on the other thread...
let (op, path) = rx.recv();
match op {
Op::REMOVE_FILE => remove_file(path),
/* ... */
}

Apply a proxy to a variable (not an attribute) using traits

This question is a near-duplicate of Apply a proxy using traits. However, that question dealt with applying a proxy to an Attribute, and I would like to do the same thing for a Variable. From Jonathan's answer, I understand that I
need to arrange for the Proxy to be bound into the attribute, so that there's a Proxy there rather than a Scalar container that is usually created by class initialization logic.
However, I can't seem to bind successfully to a Variable:D, even at compile time. (Including with nqp::bind). I'd greatly appreciate any pointers in the correct direction.
(Ideally, I'd like to support using the variable/trait with assignment syntax. In a perfect world, I'd have syntax like:
my $thing is custom-proxy = 42;
And the result of that would be that $thing is containerized inside the Proxy, but not in a Scalar. But if that's not possible, I'd settle for getting it working with binding via :=.
[EDIT: building on the accepted answer below, it is possible to mostly do this with the following code:
multi trait_mod:<is>(Variable \v, :$tom) {
v.block.add_phaser(
'ENTER',
v.willdo(<-> $_ {
$_ = Proxy.new:
STORE => -> $, $v { say "store $v" },
FETCH => { say "fetch!"; 42}
}, 1))
}
This works for variables that are not initialized to a different value or for state variables on calls to the function other than the first.
You can always bind.
my $actual-thing = 42;
my $thing := Proxy.new(
FETCH => anon method fetch () {
say 'fetch';
$actual-thing
},
STORE => anon method store ($new) {
say 'store ',$new;
$actual-thing = $new
}
);
say $thing;
$thing = 5;
say $thing;
Which currently results in the following.
fetch
fetch
fetch
fetch
fetch
fetch
fetch
42
store 5
fetch
fetch
fetch
fetch
fetch
fetch
fetch
5
(The repeated FETCH calls are a known limitation.)
If you wanted to have syntax like
my $thing is custom-proxy = 42;
You would need to start with
multi trait_mod:<is> ( Variable:D \var, :$custom-proxy! ){
…
}
The problem is that currently doing it this way requires a lot of deep Rakudo/nqp knowledge that I do not possess.
For example the code behind my $var is default('value') looks a bit like this:
multi sub trait_mod:<is>(Variable:D $v, Mu :$default!) {
my $var := $v.var;
my $what := $var.VAR.WHAT;
my $descriptor;
{
$descriptor := nqp::getattr($var, $what.^mixin_base, '$!descriptor');
CATCH {
my $native = $v.native($what);
…
}
}
…
$descriptor.set_default(nqp::decont($default));
# make sure we start with the default if a scalar
$var = $default if nqp::istype($what, Scalar);
}
Why does that have $what.^mixin_base?
I have no idea.
Why isn't $!descriptor accessible something like $v.var.descriptor?
I have no idea.
How do we change $v.var.VAR from a Scalar to a Proxy?
I have no idea.
Is that last one doable? (From within a trait_mod:<is>)
I am fairly certain that the answer is yes.
My 2d[1]:
I'd settle for getting it working with binding via :=.
sub custom-proxy is rw { Proxy.new: FETCH => { 42 }, STORE => { ... } }
my $variable := custom-proxy;
say $variable; # 42
In a perfect world, I'd have syntax like:
my $thing is custom-proxy = 42;
Aiui, that's #Larry's intent.
But, as you presumably know, if a type (eg role custom-proxy { ... }) is applied using an is trait to a scalar variable (eg my $variable is custom-proxy) then the compiler emits a compile time error message (is trait on $-sigil variable not yet implemented).
I can't seem to bind successfully to a Variable:D, even at compile time
First, let's clarify what a Variable is, and what you would need to successfully bind to:
multi trait_mod:<is>(Variable \var, :$foo!) { say var.var.VAR.WHAT } # (Scalar)
my $variable is foo;
You might think you could bind to var. But the compiler is passing an lvalue, so you're not going to be able to alter it.
You might think you could bind to var.var, which is an attribute of a Variable. (I explain what a Variable is, and its var attribute, and why I had to write "varvarVAR!" in the above code, here.)
The SO you linked shows how to alter the value bound to an attribute in some object:
$a.set_build: -> \SELF, | {
$a.set_value: SELF, Proxy.new:
STORE => -> $, $val { say "store $val" },
FETCH => { say "fetch!"; 42 }
}
So perhaps you could use that approach to alter the .var attribute of a Variable?
Unfortunately, "setting build logic" is used to "bind the attribute ... at each object creation", (hence "you'll be overriding any initial default value").
So I don't think this technique is going to help in this case because the Variable, and hence its .var attribute, has presumably already been built by the time the Variable is passed to the is trait.
In summary, while a trait is called at compile-time, I think it's called too late because the var attribute has already been permanently bound.
My guess is that altering Raku(do) so that the Variable's .var attribute becomes writable, or using metaprogramming to dive underneath Variable's public API to force through a change, would be beyond fraught, unreasonably complicating the compiler's variable handling code and/or swapping out codegen optimization logic for pessimization logic.
This may be behind #Larry's speculation that a more controlled is type on scalar variables will one day be implemented.
Footnotes
[1] My two (pennies | dogecoin).

Why does indexing need to be referenced? [duplicate]

This question already has answers here:
What is the return type of the indexing operation?
(2 answers)
Closed 2 years ago.
I'm currently learning Rust coming from JavaScript.
My problem is the following:
fn main() {
let name = String::from("Tom");
let sliced = name[..2];
println!("{}, {}", name, sliced);
}
This doesn't work. Saying "doesn't have a size known at compile-time".
To fix this I need to add & the referencing operator.
fn main() {
let name = String::from("Tom");
let sliced = &name[..2];
println!("{}, {}", name, sliced);
}
I know I need to add & before name and & is the referencing operator. But I just don't know why I actually need to do that?
By referencing a variable the reference refers to variable name but does not own it. The original value will not get dropped if my reference gets out of scope. Does that mean that the variable gets out of scope if i do name[...] and the variable gets dropped and because of that i need to create a reference to it to prevent that?
Could somebody explain me that?
I know I need to add & before name and & is the referencing operator. But I just don't know why I actually need to do that.
I understand where the confusion come from, because when you look at index() it returns &Self::Output. So it already returns a reference, what's going on?
It's because the indexing operator is syntactic sugar and uses the Index trait. However, while it uses index() which does return a reference, that is not how it is desugared.
In short x[i] is not translated into x.index(i), but actually to *x.index(i), so the reference is immediately dereferenced. That's how you end up with a str instead of a &str.
let foo = "foo bar"[..3]; // str
// same as
let foo = *"foo bar".index(..3); // str
That's why you need to add the & to get it "back" to a reference.
let foo = &"foo bar"[..3]; // &str
// same as
let foo = &*"foo bar".index(..3); // &str
Alternatively, if you call index() directly, then it isn't implicitly dereferenced of course.
use std::ops::Index;
let foo = "foo bar".index(..3); // &str
Trait std::ops::Index - Rust Documentation:
container[index] is actually syntactic sugar for *container.index(index)
The same applies to IndexMut.

Components, Isolate function, and 'referential transparency'

I have a (rather philosophical) question which refers to cyclejs components : Is isolate() referentially transparent?.
Looking at the simplified code, reproduced thereafter, I could not discriminate any source of 'impurity'. Is that because the not simplified code introduces it, or because the function would return two different objects with two different references?
In that case, would not those two objects have the same behaviour (i.e. listening and reacting to the same events on the same targets, and producing different vTree$ but which encapsulate exactly the same sequence?). And if that is so, aren't those two objects essentially the same, i.e. replacing one by the other anywhere in the program should not change anything? Which means isolate is referentially transparent? Where did I go wrong?
Actually if both calls returns different objects which cannot be substituted, how do those objects differ?
function isolate(Component, scope) {
return function IsolatedComponent(sources) {
const {isolateSource, isolateSink} = sources.DOM;
const isolatedDOMSource = isolateSource(sources.DOM, scope);
const sinks = Component({DOM: isolatedDOMSource});
const isolatedDOMSink = isolateSink(sinks.DOM, scope);
return {
DOM: isolatedDOMSink
};
};
}
I could not discriminate any source of 'impurity'. Is that because the not simplified code introduces it, or because the function would return two different objects with two different references?
The simplified code does not introduce impurity. The impurity comes from the fact that the parameter scope defaults to newScope() if it is not specified. The actual implementation of isolate() has:
function isolate(dataflowComponent, scope = newScope()) {
// ...
}
Where newScope() is:
let counter = 0
function newScope() {
return `cycle${++counter}`
}
Meaning, if the scope is not given as argument, it defaults to the next value of a hidden global counter which is incremented every time isolate() is called.
In conclusion, isolate(component, scope) is referentially transparent because we give the scope, but isolate(component) is not.

How to rewrite this in terms of R.compose

var take = R.curry(function take(count, o) {
return R.pick(R.take(count, R.keys(o)), o);
});
This function takes count keys from an object, in the order, in which they appear. I use it to limit a dataset which was grouped.
I understand that there are placeholder arguments, like R.__, but I can't wrap my head around this particular case.
This is possible thanks to R.converge, but I don't recommend going point-free in this case.
// take :: Number -> Object -> Object
var take = R.curryN(2,
R.converge(R.pick,
R.converge(R.take,
R.nthArg(0),
R.pipe(R.nthArg(1),
R.keys)),
R.nthArg(1)));
One thing to note is that the behaviour of this function is undefined since the order of the list returned by R.keys is undefined.
I agree with #davidchambers that it is probably better not to do this points-free. This solution is a bit cleaner than that one, but is still not to my mind as nice as your original:
// take :: Number -> Object -> Object
var take = R.converge(
R.pick,
R.useWith(R.take, R.identity, R.keys),
R.nthArg(1)
);
useWith and converge are similar in that they accept a number of function parameters and pass the result of calling all but the first one into that first one. The difference is that converge passes all the parameters it receives to each one, and useWith splits them up, passing one to each function. This is the first time I've seen a use for combining them, but it seems to make sense here.
That property ordering issue is supposed to be resolved in ES6 (final draft now out!) but it's still controversial.
Update
You mention that it will take some time to figure this out. This should help at least show how it's equivalent to your original function, if not how to derive it:
var take = R.converge(
R.pick,
R.useWith(R.take, R.identity, R.keys),
R.nthArg(1)
);
// definition of `converge`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj),
R.nthArg(1)(count, obj));
// definition of `nthArg`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj), obj);
// definition of `useWith`
(count, obj) => R.pick(R.take(R.identity(count), R.keys(obj)), obj);
// definition of `identity`
(count, obj) => R.pick(R.take(count, R.keys(obj)), obj);
Update 2
As of version 18, both converge and useWith have changed to become binary. Each takes a target function and a list of helper functions. That would change the above slightly to this:
// take :: Number -> Object -> Object
var take = R.converge(R.pick, [
R.useWith(R.take, [R.identity, R.keys]),
R.nthArg(1)
]);