I'm new to Dart (from JS) and I'm trying to make sense of this simple program.
When declaring variables and setting then outside in the top part of a program, it seems like (???) the assignment doesn't happen before main() is executed. See below.
List<int> a1=[1,2,3];
List<int> b1=new List.from(a1);
void main() {
a1.add(9);
print(a1); // [1,2,3,9]
print('b1 $b1'); // CONFUSING [1,2,3,9] (I expected [1,2,3])
List<int> a2=[1,2,3];
List<int> b2=new List.from(a2);
a2.add(77);
print(a2); // [1,2,3,77]
print('b2 $b2'); // [1,2,3], as expected
}
Is this because there is some Just In Time (JIT) code execution? Or that assignments happen later, like with some JS gotchas. I did try to read the docs on this but could not figure out anything with code execution order.
I'm most interested in learning how I would learn this myself. So any links to the proper section of the docs is appreciated.
PS. In JS, Chrome Developer Tools gives a handy debugger with breakpoints and I usually use this to check execution order bugs.
Thanks in advance.
It's not JIT, just lazy initialization of global variables.
Dart ensures that no user code runs before the start of main. To ensure that, it lazily initializes global and static variables the first time they are read. That does mean that you should be careful when your global variable initializer refers to mutable objects.
Related
The question came up while I was trying to write a lookup table and during debugging I had the impression, that the array might not be initialized at compile or load time, but rather in a lazy way... Unfortunately I could not find the answer in the MSDN chapter about arrays.
Lets look at some sample code first. The code is in a compiled application, not a script, btw.
module Foo =
let bar = [| for i in 0..9 -> yield (i*i) |]
When does Foo.bar get initialized?
At compile time?
At load time?
Lazy, when first accessed?
Never? (Stays an IEnumerator based sequence despite its array type?)
On a side note, my sequence expression is more complicated than the example above and also uses other functions within scope.
Are there cases which are handled in different ways, such as trivial vs complex eypression or long vs short array etc?
Foo.bar gets initialized at load time - or, when your application starts.
There are slight differences between how this is done for libraries and for applications. For applications, the compiler inserts appropriate initialization into the Main method. For libraries, the initialization check is inserted into static constructors of (I believe) all types, so when you access any type from a library, the initialization is done (this may be sometime after Main, but still before you run any code from the library).
It does not really depend on what the code is - if it is a value, it will be initialized. There are some values like Lazy<T> or IEnumerable<T> that do not immediately fully evaluate, but the value is initialized nevertheless.
This is more a simple personal attempt to understand what goes on inside Rascal. There must be better (if not already supported) solution.
Here's the code:
fileLoad = |home:///PHPAnalysis/systems/ApilTestScripts/simple1.php|;
fileAST=loadPHPFile(fileLoad,true,false);
//assign a simple id to each node
public map[value,int] assignID12(node N)
{
myID=();
visit(N)
{
case node M:
{
name=getName(M);
myID[name] =999;
}
}
return myID;
}
ids=assignID12(fileAST);
gives me
|stdin:///|(92,4,<1,92>,<1,96>): Expected str, but got value
loadPHPFile returns a node of type: list[Stmt], where each Stmt is one of the many types of statements that could occur in a program (PHP, in my case). Without going into why I'd do this, why doesn't the above code work? Especially frustrating because a very simple example is worked out in the online documentation. See: http://tutor.rascal-mpl.org/Recipes/Basic/Basic.html#/Recipes/Common/CountConstructors/CountConstructors.html
I started a new console, and it seems to work. Of course, I changed the return type from map[value,int] to map[str,int] as it was originally in the example.
The problem I was having was that I may have erroneously defined the function previously. While I quickly fixed an apparent problem, it kept giving me errors. I realized that in Rascal, when you've started a console and imported certain definitions, it (seems)is impossible to overwrite those definitions. The interpreter keeps making reference to the very first definition that you provided. This could just be the interpreter performing a type-check, and preventing unintentional and/or incompatible assignments further down the road. That makes sense for variables (in the typical program sense), but it doesn't seem like the best idea to enforce that on functions (or methods). I feel it becomes cumbersome, because a user typically has to undergo some iterations before he/she is satisfied with a function definition. Just my opinion though...
Most likely you already had the name ids in scope as having type map[str,int], which would be the direct source of the error. You can look in script https://github.com/cwi-swat/php-analysis/blob/master/src/lang/php/analysis/cfg/LabelState.rsc at the function labelScript to see how this is done in PHP AiR (so you don't need to write this code yourself). What this will give you is a script where all the expressions and statements have an assigned ID, as well as the label state, which just keeps track of some info used in this labeling operation (mainly the counter to generate a unique ID).
As for the earlier response, the best thing to do is to give your definitions in modules which you can import. If you do that, any changes to types, etc will be picked up (automatically if the module is already imported, since Rascal will reimport the module for you if it has changed, or when you next import the module). However, if you define something directly in the console, this won't happen. Think of the console as one large module that you keep adding to. Since we can have overloads of functions, if you define the function again you are really defining a new alternative to the function, but this may not work like you expect.
I am trying to use Dart to tersely define entities in an application, following the idiom of code = configuration. Since I will be defining many entities, I'd like to keep the code as trim and concise and readable as possible.
In an effort to keep boilerplate as close to 0 lines as possible, I recently wrote some code like this:
// man.dart
part of entity_component_framework;
var _man = entity('man', (entityBuilder) {
entityBuilder.add([TopHat, CrookedTeeth]);
})
// test.dart
part of entity_component_framework;
var man = EntityBuilder.entities['man']; // null, since _man wasn't ever accessed.
The entity method associates the entityBuilder passed into the function with a name ('man' in this case). var _man exists because only variable assignments can be top-level in Dart. This seems to be the most concise way possible to use Dart as a DSL.
One thing I wasn't counting on, though, is lazy initialization. If I never access _man -- and I had no intention to, since the entity function neatly stored all the relevant information I required in another data structure -- then the entity function is never run. This is a feature, not a bug.
So, what's the cleanest way of using Dart as a DSL given the lazy initialization restriction?
So, as you point out, it's a feature that Dart doesn't run any code until it's told to. So if you want something to happen, you need to do it in code that runs. Some possibilities
Put your calls to entity() inside the main() function. I assume you don't want to do that, and probably that you want people to be able to add more of these in additional files without modifying the originals.
If you're willing to incur the overhead of mirrors, which is probably not that much if they're confined to this library, use them to find all the top-level variables in that library and access them. Or define them as functions or getters. But I assume that you like the property that variables are automatically one-shot. You'd want to use a MirrorsUsed annotation.
A variation on that would be to use annotations to mark the things you want to be initialized. Though this is similar in that you'd have to iterate over the annotated things, which I think would also require mirrors.
I came across the following code the other day (below) and wondered if it achieves anything of significance in Dart other than the fact that the Class instantiation cannot be changed. I did read some SO posts regarding Java, however they didn't appear conclusive, and don't necessarily apply to Dart. I would not have coded it that way (with final), however perhaps I should. Is there any major significance to using "final" in this instance and what does it achieve?
import 'dart:math';
final _random = new Random();
From Dart: Up and Running:
If you never intend to change a variable, use final or const, either instead of var or in addition to a type. A final variable can be set only once; a const variable is a compile-time constant.
A local, top-level, or class variable that’s declared as final is initialized the first time it’s used.
So there are three benefits to using final here:
If some code erroneously tries to set _random another time, an error will be generated.
It is also clearer to other programmers (or the same programmer at a later date) that _random is never intended to be changed.
_random is not initialized until it used, so the application will start faster.
For those reasons, I would consider this a good use of final; certainly the code would "work" without it, but it's better this way.
In short, I think the book offers sound advice: "If you never intend to change a variable, use final or const".
From the documentation :
A local, top-level, or class variable that’s declared as final is initialized the first time it’s used. Lazy initialization of final variables helps apps start up faster.
Why are inline closures so rarely used in Actionscript? They are very powerful and I think quite readable. I hardly ever see anyone using them so maybe I'm just looking at the wrong code. Google uses them in their Google Maps API for Flash samples, but I think thats the only place I've seen them.
I favor them because you have access to local variables in the scope that defines them and you keep the logic in one method and dont end up with lots of functions for which you have to come up with a name.
Are there any catches of using them? Do they work pretty much the same way as in C#.
I actually only just discovered that AS3 supports them, and I'm quite annoyed becasue I had thought I read that they were deprecated in AS#. So I'm back to using them!
private function showPanel(index:int):void {
_timer = new Timer(1000, 1);
_timer.addEventListener(TimerEvent.TIMER, function(event:Event):void
{
// show the next panel
showPanel(index++);
});
The biggest gotcha to watch out for is that often 'this' is not defined in the inline closure. Sometimes you can set a 'this', but it's not always the right 'this' that you would have available to set, depending on how you're using them.
But I'd say most of the Flex code I've worked on has had inline closures rampantly throughout the code--since callbacks are the only way to get work done, and often you don't need the bring out a whole separate function.
Sometimes when the function nested is getting to be too much, I'll break it out slightly with Function variables in the function; this helps me organize a bit by giving labels to the functions but keeping some of the characteristics of inline closures (access to the local variables, for example).
Hope this helps.
One additional problem is that garbage collection is broken when it comes to closures (at least in Flash 9). The first instance of a given closure (from a lexical standpoint) will never be garbage collected - along with anything else referenced by the closure in the scope chain.
I found what originally made me NOT want to do this, but I had forgotten the details:
http://livedocs.adobe.com/flex/3/html/16_Event_handling_6.html#119539
(This is what Mitch mentioned - as far as the 'this' keyword being out of scope)
So thats Adobe's answer, however I am much more likely to need to refer to local variables than 'this'.
How do others interpret Adobe's recommendation ?