Am just starting out with Livescript and want to know how the scope works.
Are the any good example/docs that show all scope symbols and usage.
Symbols like:
#
-> vs ~>
self
:=
Edit
The problem I face:
This ethercalc code: line 103.
I want to insert a call to a Java script function, i.e. to this send email code.
http://livescript.net documents all that functionality.
# means this.
#prop means this.prop
-> creates a function, it means function(){}
-> blah() is function(){ return blah(); }
(a, b) -> foo is function(a, b) { return foo; }
self is nothing special, just the name of a variable. Often set to this of an upper scope.
:= means "reassign a variable" - it must already exist. It does not create a new variable.
Check out http://livescript.net/#introduction for more info
Related
The following example of Kotlin source code returns an error when compiled:
fun main() {
var index: Int // create an integer used to call an index of an array
val myArray = Array(5) {i -> i + 1} // create an array to call from
val condition = true // makes an if statement run true later
if (condition) {
index = 2 // sets index to 2
}
println( myArray[index] ) // should print 2; errors
}
The error says that the example did not initialize the variable index by the time it is called, even though it is guaranteed to initialize within the if statement. I understand that this problem is easily solved by initializing index to anything before the if statement, but why does the compiler not initialize it? I also understand that Kotlin is still in beta; is this a bug, or is it intentional? Finally, I am using Replit as an online IDE; is there a chance that the compiler on the website simply is an outdated compiler?
The compiler checks whether there is a path in your code that the index may not be initialized based on all the path available in your code apart from the value of the parameters. You have an if statement without any else. If you add the else statement you will not get any compile error.
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).
I want to create a Developer Variable to the workspace in Blockly, but I cannot find the necessary function/method.
I do not want to create the variable over a button. The variable should be included even if there is no block in the workspace.
With these two functions I can get the already created variables:
var variables = workspace.getAllVariables();
var dev_var = Blockly.Variables.allDeveloperVariables(workspace);
But what is the setting function?
Developer variables are variables that will never be visible to the user, but will exist in the generated code. If that's what you're looking for: there's no API for it, but here are some things you can do.
If you want to reserve the name so that users can't accidentally override your variable, call yourGenerator.addReservedWords('var1,var2,...'). You can initialize the variable in your wrapper code.
If you really want Blockly to both reserve and declare the variable for you, you could override the init function on your generator.
On the other hand, if what you want is a user-visible variable that always shows up in the toolbox, without the user creating it, you should call yourWorkspace.createVariable('variable_name').
The unit test blocks all assume that the variable unittestResults exists and can be written to. To indicate this, the block definition includes the function getDeveloperVars, which returns an array of strings. Each string is a variable name.Follow this issue in gtihub
Blockly.Blocks['unittest_fail'] = {
// Always assert an error.
init: function() {
this.setColour(65);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendDummyInput()
.appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE')
.appendField('fail');
this.setTooltip('Records an error.');
},
getDeveloperVars: function() {
return ['unittestResults'];
}
};
LINK : https://github.com/google/blockly/issues/1535
libc's error handling is usually to return something < 0 in case of an error. I find myself doing this over and over:
let pid = fork()
if pid < 0 {
// Please disregard the fact that `Err(pid)`
// should be a `&str` or an enum
return Err(pid);
}
I find it ugly that this needs 3 lines of error handling, especially considering that these tests are quite frequent in this kind of code.
Is there a way to return an Err in case fork() returns < 0?
I found two things which are close:
assert_eq!. This needs another line and it panics so the caller cannot handle the error.
Using traits like these:
pub trait LibcResult<T> {
fn to_option(&self) -> Option<T>;
}
impl LibcResult<i64> for i32 {
fn to_option(&self) -> Option<i64> {
if *self < 0 { None } else { Some(*self) }
}
}
I could write fork().to_option().expect("could not fork"). This is now only one line, but it panics instead of returning an Err. I guess this could be solved using ok_or.
Some functions of libc have < 0 as sentinel (e.g. fork), while others use > 0 (e.g. pthread_attr_init), so this would need another argument.
Is there something out there which solves this?
As indicated in the other answer, use pre-made wrappers whenever possible. Where such wrappers do not exist, the following guidelines might help.
Return Result to indicate errors
The idiomatic Rust return type that includes error information is Result (std::result::Result). For most functions from POSIX libc, the specialized type std::io::Result is a perfect fit because it uses std::io::Error to encode errors, and it includes all standard system errors represented by errno values. A good way to avoid repetition is using a utility function such as:
use std::io::{Result, Error};
fn check_err<T: Ord + Default>(num: T) -> Result<T> {
if num < T::default() {
return Err(Error::last_os_error());
}
Ok(num)
}
Wrapping fork() would look like this:
pub fn fork() -> Result<u32> {
check_err(unsafe { libc::fork() }).map(|pid| pid as u32)
}
The use of Result allows idiomatic usage such as:
let pid = fork()?; // ? means return if Err, unwrap if Ok
if pid == 0 {
// child
...
}
Restrict the return type
The function will be easier to use if the return type is modified so that only "possible" values are included. For example, if a function logically has no return value, but returns an int only to communicate the presence of error, the Rust wrapper should return nothing:
pub fn dup2(oldfd: i32, newfd: i32) -> Result<()> {
check_err(unsafe { libc::dup2(oldfd, newfd) })?;
Ok(())
}
Another example are functions that logically return an unsigned integer, such as a PID or a file descriptor, but still declare their result as signed to include the -1 error return value. In that case, consider returning an unsigned value in Rust, as in the fork() example above. nix takes this one step further by having fork() return Result<ForkResult>, where ForkResult is a real enum with methods such as is_child(), and from which the PID is extracted using pattern matching.
Use options and other enums
Rust has a rich type system that allows expressing things that have to be encoded as magic values in C. To return to the fork() example, that function returns 0 to indicate the child return. This would be naturally expressed with an Option and can be combined with the Result shown above:
pub fn fork() -> Result<Option<u32>> {
let pid = check_err(unsafe { libc::fork() })? as u32;
if pid != 0 {
Some(pid)
} else {
None
}
}
The user of this API would no longer need to compare with the magic value, but would use pattern matching, for example:
if let Some(child_pid) = fork()? {
// execute parent code
} else {
// execute child code
}
Return values instead of using output parameters
C often returns values using output parameters, pointer parameters into which the results are stored. This is either because the actual return value is reserved for the error indicator, or because more than one value needs to be returned, and returning structs was badly supported by historical C compilers.
In contrast, Rust's Result supports return value independent of error information, and has no problem whatsoever with returning multiple values. Multiple values returned as a tuple are much more ergonomic than output parameters because they can be used in expressions or captured using pattern matching.
Wrap system resources in owned objects
When returning handles to system resources, such as file descriptors or Windows handles, it good practice to return them wrapped in an object that implements Drop to release them. This will make it less likely that a user of the wrapper will make a mistake, and it makes the use of return values more idiomatic, removing the need for awkward invocations of close() and resource leaks coming from failing to do so.
Taking pipe() as an example:
use std::fs::File;
use std::os::unix::io::FromRawFd;
pub fn pipe() -> Result<(File, File)> {
let mut fds = [0 as libc::c_int; 2];
check_err(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
Ok(unsafe { (File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1])) })
}
// Usage:
// let (r, w) = pipe()?;
// ... use R and W as normal File object
This pipe() wrapper returns multiple values and uses a wrapper object to refer to a system resource. Also, it returns the File objects defined in the Rust standard library and accepted by Rust's IO layer.
The best option is to not reimplement the universe. Instead, use nix, which wraps everything for you and has done the hard work of converting all the error types and handling the sentinel values:
pub fn fork() -> Result<ForkResult>
Then just use normal error handling like try! or ?.
Of course, you could rewrite all of nix by converting your trait to returning Results and including the specific error codes and then use try! or ?, but why would you?
There's nothing magical in Rust that converts negative or positive numbers into a domain specific error type for you. The code you already have is the correct approach, once you've enhanced it to use a Result either by creating it directly or via something like ok_or.
An intermediate solution would be to reuse nix's Errno struct, perhaps with your own trait sugar on top.
so this would need another argument
I'd say it would be better to have different methods: one for negative sentinel values and one for positive sentinel values.
The following code works correctly - output: You chose Test 1
package main
import (
"fmt"
)
type TNameMap map[int]string
var nameMap TNameMap
func init() {
nameMap = make(TNameMap)
nameMap[1] = "You chose Test 1"
nameMap[2] = "You chose Test 2"
nameMap[3] = "You chose Test 3"
}
func main() {
fmt.Println(nameMap[1])
}
If I comment out the first line in init() i.e //nameMap = make(TNameMap) , I get a panic when main() runs, because nameMap was never initialized:
panic: runtime error: assignment to entry in nil map
But - if in init() I write nameMap := make(TNameMap)
instead of nameMap = make(TNameMap) , I get no panic, but also no output - main() simply runs and process terminates.
I understand that if I use the Initialization operator - nameMap := make(TNameMap) - I have declared a new variable nameMap that is scoped only to the init() function and so only the package level variable var nameMap TNameMap is in scope for main(), resulting in no output, because the package level var holds no map data.
But, I am confused: Why don't I get the panic in that situation? If main() is making the call on the package var, it was never initialized - so why no panic?
According to the Go spec:
A nil map is equivalent to an empty map except that no elements may be
added.
This means that you can read from a nil map, but not write. Just like the panic says "assignment to entry in nil map". If you comment out just the line nameMap = make(TNameMap) it will crash because you attempt to write to it in init (which is where the panic happens). If you comment out the entirety of init the Println will not crash because you're permitted to access (read from) a nil map.
Changing the assignment to a declaration is just masking the real issue here, what's happening is it's making all the assignments valid, and then discarding the result. As long as you make the assignments valid (either by removing them or making a temporary variable), then you will observe the same behavior in Println.
The value returned by a nil map is always the zero value of the value type of the map. So a map[T]string returns "", a map[T]int returns 0, and so on. (Of course, if you check with val,ok := nilMap[key] then ok will be false).