I really can't find another explanation for this:
for <a b> -> $foo {
spurt "a/b", "bar";
}
say "Gotcha";
for <a b> {
spurt "a/b", "bar";
}
This prints "Gotcha" and then fails. I get that the last value in a loop is returned, and that if nothing is done with it it's in sink context, but what kind of change brings declaring a variable to it? It's still a Block, far as I can tell.
Related
The documentation probably explains it very well but I do not see the difference between this 2 commands in my case :
method dir {} {
puts "method dir..."
}
method pseudomethod {} {
set vardir [my dir]
set vardir [[self] dir]
}
The only difference I can see is that with [self] I can pass it as an argument in a procedure and not with my.
What is the best solution in my case ?
Both solutions have equal performance ?
The self command (with no extra arguments) is equivalent to self object which returns the current public name of the object that is executing the method (you can rename the object). The self command overall provides access to bits of “runtime” state.
The my command is actually the object's internal name; it's created in each object's instance namespace. You can invoke all exported and non-exported methods via my, unlike with the public name. This makes it useful for both calling your internal methods directly, and also for setting up things like callbacks to internal methods (you'll need something like namespace which or namespace code when setting up the callback).
Unlike with the public name, you can delete the internal name command without automatically destroying the object. It'll likely break code (your methods most probably) if you do that, but the base system allows you to do it.
Aside: Tcl 8.7 includes this helper procedure (which also works in 8.6) for creating callback scripts within methods (the funny name means it gets mapped into your methods automatically as callback):
proc ::oo::Helpers::callback {method args} {
list [uplevel 1 {::namespace which my}] $method {*}$args
}
In this case, if the callback was exported, you'd be able to do this instead:
proc ::oo::Helpers::callback {method args} {
list [uplevel 1 self] $method {*}$args
}
but that would be more vulnerable to rename problems. (In all cases, the uplevel 1 is because we want to run a little bit of name-resolving code in the calling context, not inside the scope of the procedure itself.)
I'm not sure how they are implemented, but one reason you'd want to use my is to access non-exported (private) methods. A demo:
oo::class create Foo {
method PrivateMethod {} {puts "this is PrivateMethod"}
method publicMethod {} {puts "this is publicMethod"}
method test {} {
my publicMethod
my PrivateMethod
[self] publicMethod
[self] PrivateMethod
}
}
then:
% Foo create foo
::foo
% foo test
this is publicMethod
this is PrivateMethod
this is publicMethod
unknown method "PrivateMethod": must be destroy, publicMethod or test
my is the mechanism for an object to invoke its methods.
self is the mechanism for introspection on how the current method was called.
Spend some time with the my and self man pages.
if ($condition)
$foo = 'bar';
else
throw_exception();
echo $foo;
For this of code, PhpStorm thinks that $foo might not be defined and shows a warning. I have to add /** #noinspection PhpUndefinedVariableInspection */ to eliminate the warning that I hope there is a better solution.
ATM -- nope.
https://youtrack.jetbrains.com/issue/WI-10673 might be a solution (once it will be implemented).
Right now even declaring throw_function() with #throws Exception does not help (as throwing an exception is just one of the possible scenarios and not an obligation).
Watch that and the following related tickets (star/vote/comment) to get notified on any progress:
https://youtrack.jetbrains.com/issue/WI-7462
https://youtrack.jetbrains.com/issue/WI-6562
Right now I simply suggest to rewrite the code in a following more straightforward and easier-to-read fashion:
if (!$condition) {
throw_exception();
}
$foo = 'bar';
echo $foo;
If condition is not met then exit happens sooner (due to the thrown exception) and the code below will simply not be executed. It's much easier to read and understand this way (to follow the code execution flow).
I think PhpStorm is right, because if you don't meet the $condition then $foo is undefined.
You could declare $foo with a null value (or false, or ' ' ...) before the if block to avoid the warning (IMHO this is a better solution):
$foo = '';
if ($condition)
$foo = 'bar';
else
throw_exception();
echo $foo;
(See this more as a comment than an answer please)
As atx stated it's because $foo is not definied when it's read. This is called an undefinied read data flow anomaly. That's not a "problem" of PHPStorm or any other IDE but of your code or in more general of the PHP syntax. The static code analysis in the else-case only see a method call of a method calles throw_exception, not the end of the script. Therefore your code looks like this in this case:
throw_exception();
echo $foo
And then you read an unfedinied variable.
Let's compare this to to a JAVA example
public void test(boolean condition) throws Exception {
if (condition) {
String foo = "this";
} else {
throw new Exception("");
}
// Doesn't compile: foo can not be resolved to a variable
System.out.println(foo);
}
This does not compile at all, because in the line of printing foo "foo can not be resolved to a variable". Same when this method doesn't throws an exception but exits the method with a return value:
public boolean test(boolean condition) {
if (condition) {
String foo = "this";
} else {
return false;
}
// Doesn't compile: foo can not be resolved to a variable
System.out.println(foo);
return true;
}
Let's extend the example:
public void test(boolean condition, String foo) {
if (condition) {
foo = "this";
} else {
System.out.println("else");
}
System.out.println(foo);
}
This compiles and you don't get a warning of the static code analysis because the static code analysis doesn't see an ur-anomaly: foo ist definied in the method header, even if it's definied as null.
Hope this helps to understand why you get the warning and should always definie your variables.
I was struggling to describe this succintly in the title so I'll paste in my typescript code that achieves what I'm talking about -
aggregate<T, A>(args: A[], invokable: (arg: A) => promise<T>): promise<T[]> {
let allPromises = new Array<promise<T>>();
for (let arg of args) {
allPromises.push(invokable(arg));
}
return promise.all(allPromises);
}
This takes a list of arguments of type A and for each of them invokes some function (which returns a promise which returns type T). Each of these promises are collected into a list which is then all-ified and returned.
My question is, does this function already exist in Bluebird as I'd rather do things properly and use that existing, tested functionality! I had problems getting my head around some of the documentation so I might not have grokked something I should have!
Your problem is perfectly solvable with Array.prototype.map.
Your code can be turned into:
aggregate<T, A>(args: A[], invokable: (arg: A) => promise<T>): promise<T[]> {
return promise.all(args.map(invocable));
}
I am trying to understand how you return non-primitives (i.e. types that do not implement Copy). If you return something like a i32, then the function creates a new value in memory with a copy of the return value, so it can be used outside the scope of the function. But if you return a type that doesn't implement Copy, it does not do this, and you get ownership errors.
I have tried using Box to create values on the heap so that the caller can take ownership of the return value, but this doesn't seem to work either.
Perhaps I am approaching this in the wrong manner by using the same coding style that I use in C# or other languages, where functions return values, rather than passing in an object reference as a parameter and mutating it, so that you can easily indicate ownership in Rust.
The following code examples fails compilation. I believe the issue is only within the iterator closure, but I have included the entire function just in case I am not seeing something.
pub fn get_files(path: &Path) -> Vec<&Path> {
let contents = fs::walk_dir(path);
match contents {
Ok(c) => c.filter_map(|i| { match i {
Ok(d) => {
let val = d.path();
let p = val.as_path();
Some(p)
},
Err(_) => None } })
.collect(),
Err(e) => panic!("An error occurred getting files from {:?}: {}", pa
th, e)
}
}
The compiler gives the following error (I have removed all the line numbers and extraneous text):
error: `val` does not live long enough
let p = val.as_path();
^~~
in expansion of closure expansion
expansion site
reference must be valid for the anonymous lifetime #1 defined on the block...
...but borrowed value is only valid for the block suffix following statement
let val = d.path();
let p = val.as_path();
Some(p)
},
You return a value by... well returning it. However, your signature shows that you are trying to return a reference to a value. You can't do that when the object will be dropped at the end of the block because the reference would become invalid.
In your case, I'd probably write something like
#![feature(fs_walk)]
use std::fs;
use std::path::{Path, PathBuf};
fn get_files(path: &Path) -> Vec<PathBuf> {
let contents = fs::walk_dir(path).unwrap();
contents.filter_map(|i| {
i.ok().map(|p| p.path())
}).collect()
}
fn main() {
for f in get_files(Path::new("/etc")) {
println!("{:?}", f);
}
}
The main thing is that the function returns a Vec<PathBuf> — a collection of a type that owns the path, and are more than just references into someone else's memory.
In your code, you do let p = val.as_path(). Here, val is a PathBuf. Then you call as_path, which is defined as: fn as_path(&self) -> &Path. This means that given a reference to a PathBuf, you can get a reference to a Path that will live as long as the PathBuf will. However, you are trying to keep that reference around longer than vec will exist, as it will be dropped at the end of the iteration.
How do you return non-copyable types?
By value.
fn make() -> String { "Hello, World!".into() }
There is a disconnect between:
the language semantics
the implementation details
Semantically, returning by value is moving the object, not copying it. In Rust, any object is movable and, optionally, may also be Clonable (implement Clone) and Copyable (implement Clone and Copy).
That the implementation of copying or moving uses a memcpy under the hood is a detail that does not affect the semantics, only performance. Furthermore, this being an implementation detail means that it can be optimized away without affecting the semantics, which the optimizer will try very hard to do.
As for your particular code, you have a lifetime issue. You cannot return a reference to a value if said reference may outlive the value (for then, what would it reference?).
The simple fix is to return the value itself: Vec<PathBuf>. As mentioned, it will move the paths, not copy them.
I want to return from a configbody but cannot do so explicitly without causing the variable not to be set.
I'd like help understanding the behavior I'm seeing. Please consider the following code (using Itcl 3.4):
package require Itcl
catch {itcl::delete class Model}
itcl::class Model {
public variable filename "orig"
}
itcl::configbody Model::filename {
if 1 {
return ""
} else {
}
}
Model my_model
my_model configure -filename "newbie"
puts "I expect the result to be 'newbie:' [my_model cget -filename]"
When I return empty string, filename is not set to the new value. If I do not return but just allow the proc to fall through, filename does change. You can see this by changing the 1 to a 0 in the above code.
I suspect its related to the following statement:
When there is no return in a script, its value is the value of the last command evaluated in the script.
If someone would explain this behavior and how I should be returning, I'd appreciate the help.
Tcl handles return by throwing an exception (of type TCL_RETURN). Normally, the outer part of a procedure or method handler intercepts that exception and converts it into a normal result of the procedure/method, but you can intercept things with catch and see beneath the covers a bit.
However, configbody does not use that mechanism. It just runs the script in some context (not sure what!) and that context treats TCL_RETURN as an indication to fail the update.
Workaround:
itcl::configbody Model::filename {
catch {
if 1 {
return ""
} else {
}
} msg; set msg
# Yes, that's the single argument form of [set], which READS the variable...
}
Or call a real method in the configbody, passing in any information that's required.