Why can't I map Path::new over the std::env::args iterator? - iterator

This works:
let paths: Vec<String> = args.collect();
let paths = paths.iter().map(|f| std::path::Path::new(&f));
This doesn't work:
let paths = ::std::env::args().map(|f| std::path::Path::new(&f));
error[E0597]: `f` does not live long enough
--> src/main.rs:2:66
|
2 | let paths = ::std::env::args().map(|f| std::path::Path::new(&f));
| ^-- borrowed value needs to live until here
| ||
| |`f` dropped here while still borrowed
| borrowed value does not live long enough
Why do I need to collect the args iterator into a vector just to produce another iterator? Why can't I produce one iterator directly from another?

The Args iterator returns values of type String. When you map over an iterator, the closure is given ownership of each value.
The code that doesn't work attempts to take a reference to the String, but that string will go out of scope at the end of the closure. This is disallowed as discussed in Return local String as a slice (&str).
The code that does work is not iterating over Strings but &Strings; see What is the difference between iter and into_iter?. Thus there's nothing to go out of scope in the closure and returning a reference from the closure is fine.
The correct solution is to transfer ownership of the String's data to a new type. PathBuf is the appropriate choice. PathBuf is to &Path as String is to &str:
let paths = ::std::env::args().map(std::path::PathBuf::from);
PathBuf is mutable. I don't need mutability here. Why do you think I need PathBuf?
You are confused about how mutability works in Rust. Go back and re-read The Rust Programming Language, especially the chapter on Variables and Mutability.
Types in Rust are not mutable or immutable by themselves. Mutability is a property of the variable binding:
let buf = std::path::PathBuf::new();
buf.push("home");
error[E0596]: cannot borrow immutable local variable `buf` as mutable
--> src/main.rs:3:5
|
2 | let buf = std::path::PathBuf::new();
| --- consider changing this to `mut buf`
3 | buf.push("home");
| ^^^ cannot borrow mutably

Related

Is the term immutable variable just a convention?

In Rust variables are immutable by default, i.e., they don't vary but are not constants (as noted here).
Do they retain the name "variable" just by convention, or is there another reason why the term "variable" is maintained?
It should be noted that the term mut in Rust was hotly debated before stabilization with some arguing that it should be called excl or uniq. The matter is that the mut in in let mut x and &mut x are two completely different things.
let mut x declares that x is mutable, in the sense that it can be re-assigned, but also that one can take a &mut reference of it; which is best called an exclusive or unique reference. It is quite possible in Rust in some cases to mutate through a shared reference in the case of std::cell::Cell, for instance, and not all operations that require an exclusive reference involve mutation. An operation that requires an exclusive reference is simply one that would be unsafe with a shared one; Cell is designed in such a way that it is not, by strictly controlling under what conditions mutation can occur.
In theory, the two functions of let mut x could have different keywords, but they are compressed into one for simplicity. Rust could in theory be designed with mut and excl being different keywords, and allowing for let excl x, which would be a variable wherefrom one could take an exclusive reference, but not mutate.
One can also have variables that are not declared with mut, in particular in function calls. In a signature like fn func ( x : u32 ), x is not mutable, but it is variable, because it a different x can be passed every single time.
The let mut x type of "mutable" is purely a lint and, in theory, unnecessary for Rust to work — any currently working Rust program will continue to work if all non-mutable variables be made mutable. It's simply considered bad practice to do so and the compiler will warn the programmer whenever he make a variable mutable that isn't necessary to be mutable; this helps catching unintended bugs. This is absolutely not the case with exclusive and shared references, which are necessary to be distinguished and more than just a lint.
Here "variable" means "factor involved in computation" not "varying". This is from the mathematical principle where expressions like f(x) include x, a variable, as a part of the equation.
In Rust, like with other languages, you'll need variables (e.g. input) that affects how the program runs, otherwise your program would only ever behave in a singular, specific way, producing the same output each time.
You'll need to think of what variables change during processing and which do not. Those that do not need to change do not need to be declared mutable.
Regardless of if or when they change, they're still considered variables.
In C++ you'll have things like const int x which is a constant (read-only) variable, so the term can take on all sorts of specific meanings.
Is the term immutable variable just a convention?
By definition every... definition of a word is a convention, language, meaning of the word, change by time, is unique for every people that live, you can take 100 peoples and end with 100 difference definition of 1 word. That why we often start scientific paper by defining word that could be miss understand in the paper. Trying to clarify as much as possible. Rust does not differs that why we have The Reference
We have a specific section for variable
A variable is a component of a stack frame, either a named function
parameter, an anonymous temporary, or a named local variable.
A local variable (or stack-local allocation) holds a value directly,
allocated within the stack's memory. The value is a part of the stack
frame.
Local variables are immutable unless declared otherwise. For example:
let mut x = ....
Function parameters are immutable unless declared with mut. The mut
keyword applies only to the following parameter. For example: |mut x,
y| and fn f(mut x: Box, y: Box) declare one mutable variable
x and one immutable variable y.
Local variables are not initialized when allocated. Instead, the
entire frame worth of local variables are allocated, on frame-entry,
in an uninitialized state. Subsequent statements within a function may
or may not initialize the local variables. Local variables can be used
only after they have been initialized through all reachable control
flow paths.
So there is not much to add, variable in rust is clearly defined, it doesn't matter if your definition doesn't match or you find a definition of variable that doesn't match Rust one. In the context of Rust, variable is that. If you want to ask about opinion about this choice then it's off topic as opinion oriented. But, wiki definition make Rust definition quite standard both from mathematics view than computer science:
Variable (computer science), a symbolic name associated with a value and whose associated value may be changed
Variable (mathematics), a symbol that represents a quantity in a mathematical expression, as used in many sciences

Why do I have to specify the type for "const" variables but not for "let" variables?

To create a variable in Rust you'd use:
let var_name = 10;
This would also be valid:
let var_name: i32 = 10;
Constant variables are created like this:
const VAR_NAME: i32 = 10;
But if you tried to create a constant variable like this:
const VAR_NAME = 10;
You'd get an error that looks like this:
error: expected `:`, found `=`
--> src/main.rs:5:11
|
4 | const VAR_NAME = 10;
| ^ expected `:`
Having come from languages like JavaScript, Python & PHP this is kind of confusing to me.
Why is it that I have to specify a type definition when using const but not when I use let?
Currently, there is a rule "Constants must be explicitly typed." (for static: "A static item is similar to a constant").
But, you are right: the compiler could infer it. There is an open discussion about that: #1349, TL;DR:
We could technically infer the type of const and static variable
We do not use them very often so it's not very annoying to annotate the types
We should maybe limit type inference for constants/statics to only literal value
This could make error messages less accurate
Maybe limit type inference for constants/statics to local scopes like function bodies
For integers, const FOO = 22 would infer to i32 so probably not the type one would expect. So we'd end up writing const FOO = 22usize.
When the variable is initialized with a const-fn, the type should be inferred
When the variable is initialized with another variable typed explicitly
For arrays, the explicit type is very redundant
For variables which are only exported, we can end up not being able to infer their types (so it would be a compile-time error "type needs to be specified")
It may be worth mentioning that one of the guiding principle of type inference in Rust is that type inference should be local. This is the reason why, unlike in Haskell, function signatures always need to be fully specified. There are multiple reasons for this, notably it means easier reasoning for human readers and better error messages. This puts module level const in a tough spot, inference-wise. Matthieu M.
So far, there is still not a proposed RFC, so this issue stays open.
See also:
Why does Rust not permit type inference for local constants?

Get a name of a method parameter using Javassist

I have a CtMethod instance, but I don't know how to get names of parameters (not types) from it. I tried getParameterTypes, but it seems it returns only types.
I'm assuming it's possible, because libraries I'm using don't have sources, just class files and I can see names of method parameters in IDE.
It is indeed possible to retrieve arguments' names, but only if the code has been compiled with debug symbols otherwise you won't be able to do it.
To retrieve this information you have to access the method's local variable table. For further information about this data structure I suggest you to check section 4.7.13. The LocalVariableTable Attribute of the jvm spec. As I usually say, JVM spec may look bulky but it's an invaluable friend when you're working at this level!
Accessing the local variable table attribute of your ctmethod
CtMethod method = .....;
MethodInfo methodInfo = method.getMethodInfo();
LocalVariableAttribute table = methodInfo.getCodeAttribute().getAttribute(javassist.bytecode.LocalVariableAttribute.tag);
You now have the the local variable attribute selected in table variable.
Detecting the number of localVariables
int numberOfLocalVariables = table.tableLenght();
Now keep in mind two things regarding the number in numberOfLocalVariables:
1st: local variables defined inside your method's body will also be accounted in tableLength();
2nd: if you're in a non static method so will be this variable.
The order of your local variable table will be something like:
|this (if non static) | arg1 | arg2 | ... | argN | var1 | ... | varN|
Retriving the argument name
Now if you want to retrieve, for example, the arg2's name from the previous example, it's the 3rd position in the array. Hence you do the following:
// remember it's an array so it starts in 0, meaning if you want position 3 => use index 2
int frameWithNameAtConstantPool = table.nameIndex(2);
String variableName = methodInfo.getConstPool().getUtf8Info(frameAtConstantPool)
You now have your variable's name in variableName.
Side Note: I've taken you through the scenic route so you could learn a bit more about Java (and javassists) internals. But there are already tools that do this kind of operations for you, I can remember at least one by name called paranamer. You might want to give a look at that too.
Hope it helped!
If you don't actually want the names of the parameters, but just want to be able to access them, you can use "$1, $2, ..." as seen in this tutorial.
It works with Javaassist 3.18.2 (and later, at least up to 3.19 anyway) if you cast, like so:
LocalVariableAttribute nameTable = (LocalVariableAttribute)methodInfo.getCodeAttribute().getAttribute(LocalVariableAttribute.tag);

Error: Cannot safely evaluate the definition of the recursively-defined module

I'm curious to understand why this error happens and which is the best way to get around it.
I have a couple of files types.ml and types.mli which define a variant type value that can be of many different builtin OCaml types (float, int, list, map, set, etc..).
Since I have to use the std-lib over this variant type I needed to concretize the Set module through the functor to be able to use sets of value type by defining the ValueSet module.
The final .ml file is something like:
module rec I :
sig
type value =
Nil
| Int of int
| Float of float
| Complex of Complex.t
| String of string
| List of (value list) ref
| Array of value array
| Map of (value, value) Hashtbl.t
| Set of ValueSet.t ref
| Stack of value Stack.t
...
type t = value
val compare : t -> t -> int
end
= struct
(* same variant type *)
and string_value v =
match v with
(* other cases *)
| Set l -> sprintf "{%s} : set" (ValueSet.fold (fun i v -> v^(string_value i)^" ") !l "")
end
and OrderedValue :
sig
type t = I.value
val compare : t -> t -> int
end
= struct
type t = I.value
let compare = Pervasives.compare
end
and ValueSet : Set.S with type elt = I.value = Set.Make(I)
As you can see I had to define the ValueSet module from the functor to be able to use that datatype. The problem occurs when I want to use that module inside the declaration of I. So that I obtain the following error:
Error: Cannot safely evaluate the definition of the recursively-defined module I
Why does this happen? Which is a good way to solve it? And just to know, is my approach to what I'm trying to do correct? Apart from that it works as intended (I'm able to use the ValueSet type with my operations in other modules, but I have to comment the involved line in types.ml to pass compilation phase).
I tried to remove all the superfluous code and reduce the code to essential needed to investigate this error.. if it's not enought just ask :)
EDIT: according to OCaml reference we have that
Currently, the compiler requires that all dependency cycles between the recursively-defined module identifiers go through at least one “safe” module. A module is “safe” if all value definitions that it contains have function types typexpr1 -> typexpr2.
This is everything I found so far, but I don't get the exact meaning..
Thank in advance
After fixing the obvious errors, your example does compile (with OCaml 3.10, but I think this hasn't changed since recursive modules were introduced in 3.07). Hopefully my explanations below will help you find what, amongst the definitions you left out, caused your code to be rejected.
Here is some example code that is accepted:
module rec Value : sig
type t =
Nil
| Set of ValueSet.t
val compare : t -> t -> int
val nil : t
(*val f_empty : unit -> t*)
end
= struct
type t =
Nil
| Set of ValueSet.t
let compare = Pervasives.compare
let nil = Nil
(*let f_empty () = Set ValueSet.empty*)
end
and ValueSet : Set.S with type elt = Value.t = Set.Make(Value)
At the expression level, the module Value has no dependency on ValueSet. Therefore the compiler generates the code to initialize Value before the code to initialize Value, and all goes well.
Now try commenting out the definition of f_empty.
File "simple.ml", line 11, characters 2-200:
Cannot safely evaluate the definition of the recursively-defined module Value
Now Value does depend on ValueSet, and ValueSet always depends on Value because of the compare function. So they are mutually recursive, and the “safe module” condition must apply.
Currently, the compiler requires that all dependency cycles between the
recursively-defined module identifiers go through at least one "safe" module. A
module is "safe" if all value definitions that it contains have function types
typexpr_1 -> typexpr_2.
Here, ValueSet isn't safe because of ValueSet.empty, and Value isn't safe because of nil.
The reason to the “safe module” condition is the chosen implementation technique for recursive module:
Evaluation of a recursive module definition proceeds
by building initial values for the safe modules involved, binding all
(functional) values to fun _ -> raise Undefined_recursive_module. The defining
module expressions are then evaluated, and the initial values for the safe
modules are replaced by the values thus computed.
If you comment out the declaration of nil in the signature of Value, you can leave the definition and declaration of f_empty. That's because Value is now a safe module: it contains only functions. It's ok to leave the definition of nil in the implementation: the implementation of Value is not a safe module, but Value itself (which is its implementation coerced to a signature) is safe.
I'm really not sure what kind of syntax you're using in the signature that allows let ... I'm going to assume it was a mistake while reducing the code for us. You also don't need that OrderedType definition, possibly another fiddling error for us, since you don't use it in parameterisation of the Set module.
Aside from that, I have no problem running the following in the toplevel. Since this works pretty directly, I am unsure how you're getting that error.
module rec Value :
sig
type t =
| Nil
| Int of int
| Float of float
| String of string
| Set of ValueSet.t
val compare : t -> t -> int
val to_string : t -> string
end = struct
type t =
| Nil
| Int of int
| Float of float
| String of string
| Set of ValueSet.t
let compare = Pervasives.compare
let rec to_string = function
| Nil -> ""
| Int x -> string_of_int x
| Float x -> string_of_float x
| String x -> x
| Set l ->
Printf.sprintf "{%s} : set"
(ValueSet.fold (fun i v -> v^(to_string i)^" ") l "")
end
and ValueSet : Set.S with type elt = Value.t = Set.Make (Value)

Does any dialect of Pascal allow a variable number of arguments?

This is a question for the older programmers.
Years ago, I encountered a dialect of Pascal which allowed a variable number of arguments, through some kind of extension.
Does anyone know of a current dialect of Pascal which allows a variable number of arguments?
Given that Pascal is not as popular as it used to be, I wouldn't be surprised if the answer is no.
BTW, it is more correct, isn't it, to say variable number of arguments, rather than parameters ?
No. The answer is based on the Pascal dialects that I have used; others may be different.
The reason is that Pascal pushes arguments onto the stack frame in order, so all arguments are accessed via a fixed offset from the stack pointer. C, by comparison, pushes arguments in reverse order, so defined parameters are at fixed offset, and you can access "extra" arguments via pointer arithmetic. I'll try some ASCII art:
Pascal C
---------------------
| extra arg |
--------------------- ---------------------
| 1st param | | 3rd param |
--------------------- ---------------------
| 2nd param | | 2nd param |
--------------------- ---------------------
SP -> | 3rd param | | 1st param |
--------------------- ---------------------
As for parameter versus argument: as I learned it, the function (method) defines its parameters, the caller passes arguments. That definition came, I believe, from a Fortran manual, so that should give you an idea of how old I am :-)
You can use optional arguments with delphi to get the same effect:
procedure Proc(const A: Integer; const B: Integer = 15);
Proc(10); // B = 15
Proc(20,30);
Or overloaded methods:
procedure Proc(const A: Integer); overload;
procedure Proc(const A,B: Integer); overload;
Proc(10); // Variant 1
Proc(20,30); // Variant 2
Or you can use a variable array for parameters:
procedure Message(const AMessage: string; const AArgs: array of const);
Message('Hello %s', [Name]);
Message('%s %s', [Greeting, Name]);
GNU-Pascal (gcc based) afaik maps 1:1 to C support. using function something(arg:pchar;...) like syntax
Delphi/Free Pascal has "array of const" support, which is a typesafe version, and a varargs directive for the C interfacing (D6 or D7+)
You are probably thinking of a library that was available for Turbo Pascal where they had a hack like this. My syntax is a bit a rusty for objects and descending from it.
type
TValue = object;
TInteger = object(TValue)
Value : Integer;
end
TString = object(TValue)
Value : String;
end
TParam = record
Value : TValue;
Param : TParam;
end;
TValue = object;
{ Definition of Function }
function Test (Arg : TParam);
{ Usage }
var
I : TInteger;
S : TString;
Test (TParam (I, TParam (S, nil));
You could just chain as many arguments as you wanted. The last one had to be terminated with nil.
Yes!
Use the params keyword:
procedure write(params args: array of Object);
begin
{...}
end;