There is no detalied explanation of what exactly es6 import and export do under the hood. Someone describe import as an read only view. Check the code below:
// lib/counter.js
export let counter = 1;
export function increment() {
counter++;
}
export function decrement() {
counter--;
}
// src/main.js
import * as counter from '../../counter';
console.log(counter.counter); // 1
counter.increment();
console..log(counter.counter); // 2
My question is if two modules import the same counter module and the first module increment the counter, will the second module also see the the counter as incremented? What under hood do the "import" and "export" do? Under what context is the increment function executing on? What is variable object of the increment function?
// lib/counter.js
export let counter = 1;
export function increment() {
counter++;
}
export function decrement() {
counter--;
}
// src/main1.js
import * as counter from '../../counter';
console.log(counter.counter); // 1
counter.increment();
console..log(counter.counter); // 2
// src/main2.js
import * as counter from '../../counter';
console.log(counter.counter); // what is the result of this, 1 or 2?
It seems to me that the "export" is creating a global object that can be accessed by different modules and it is setting the context of the exported function to that object. If this is the case, the design is wired for me, because modules is not aware of what other modules do. If two modules are importing the same module(counter), one module calls the increment function(example above) which cause the value(counter) changed, the other module does not know that.
See section 16.3.5 here
As mentioned:
The imports of an ES6 module are read-only views on the exported entities. That means that the connections to variables declared inside module bodies remain live, as demonstrated in the following code.
//------ lib.js ------
export let counter = 3;
export function incCounter() {
counter++;
}
//------ main.js ------
import { counter, incCounter } from './lib';
// The imported value `counter` is live
console.log(counter); // 3
incCounter();
console.log(counter); // 4
How that works under the hood is explained in a later section.
Imports as views have the following advantages:
They enable cyclic dependencies, even for unqualified imports.
Qualified and unqualified imports work the same way (they are both
indirections).
You can split code into multiple modules and it will
continue to work (as long as you don’t try to change the values of
imports).
The answer depends on what is your entry module. For example, if you define an entry module as:
// index.js
import "./main1";
import "./main2";
Then the output is:
1 // from main1
2 // from main1
2 // from main2
ES6 modules are allowed hold state, but are not allowed to manipulate others modules state directly. The module itself can expose a modifier function (like your increment method).
If you want to experiment a bit, rollupjs has a nice online demo that shows how the standard imports and exports should work.
Related
If we take for example the following code excerpt (at the top of a module):
val write_indices = WireInit(VecInit(Seq.fill(wordsPerBeat)(0.U((log2Ceil(nWays)+log2Ceil(nSets)+log2Ceil(cacheBlockBytes/wordBytes)).W))))
val write_line_indices = WireInit(VecInit(Seq.fill(wordsPerBeat)(0.U(log2Ceil(cacheBlockBytes/wordBytes).W))))
dontTouch(write_indices)
dontTouch(write_line_indices)
// refill logic
when(mem_response_present) {
for (i <- 0 until wordsPerBeat) {
val beatIdx = i.U(log2Ceil(wordsPerBeat).W)
val write_line_index = Cat(d_refill_cnt(log2Ceil(cacheBlockBytes/wordsPerBeat/wordBytes)-1, 0), beatIdx)
val write_idx = Cat(refill_way, refill_set, write_line_index)
write_indices(i) := write_idx
write_line_indices(i) := write_line_index
cache_line(write_idx) := tl_out.d.bits.data((i + 1) * wordBits - 1, i * wordBits)
}
}
The only reason for the two top level signals is to get lower signals visible in waveforms.
Is there any way to achieve the same effect without having to manually create those signals?
In this example half the code is used just to get the ability to debug.
That seems a bit excessive.
That seems a bit excessive
Completely agreed, fortunately there is a solution. For implementation reasons, Chisel by default is only able to name public fields of the Module class. That is, only the values at the the top-level scope of your Module. However, there is a nifty macro chisel3.experimental.chiselName that can name these vals inside of the for loop. Try annotating your Module like so:
import chisel3._
import chisel3.experimental.chiselName
#chiselName
class MyModule extends Module {
...
}
Please check out this earlier answer discussing naming, it has more information than is relevant to answer this question alone, but it has other useful information about how naming works in Chisel.
I want to create a global function that can be called anywhere in my other qml files. Have tried to put a function inside of a rectangle, but it gives me syntax error in the next object. I don't want to use singleton because the syntax would be like Singleton.foobar. I just want to use foobar at anywhere in other qml.
Rectangle {
function foobar(v) {
return v * 2;
}
}
ApplicationWindow { // syntax error here
}
Define the function in your root-node (ApplicationWindow).
This will be the last place, QML will look for a name, before it resorts to the C++-context properties.
See here to find out, how the names of variables and functions are resolved in QML.
It is not possible however to modify the global object, so true global JS-functions are not possible.
The more efficient approach however would be, to keep it always in one of the moste specific scopes, so referencing it with Identifyer.function() would be faster to look up. The singleton for libraries however is not the way to go. Look here for the usage of JS libraries.
Create C++ class with invokable function:
...
class MyCPPObject : public QObject
{
Q_OBJECT
public:
...
Q_INVOKABLE bool funToCallFromJS(int any, QString args);
...
Create MyCPPObject object in global space (rule is following: it must exist until engine exists (it's some simplification, but enough))
...
MyCPPObject cppobj;
...
Use following code to export it to qml and js:
...
QJSValue wrapobj = engine.newQObject(&cppobj);
engine.globalObject().setProperty("cppFun", wrapobj.property("funToCallFromJS"));
...
wrapobj also must exists while engine exists (again simplification)
4. In qml and JS:
...
if(cppFun(127, "abc"))
console.log("It works!");
...
Note: i used different names in qml space and cpp space just to show it's possible to rename cpp function when it used from js, but you can use same name, of course.
In my application I'll need to create a functions library to be accessed from different components. What is the best way to do this? Do I need to make a service with all the functions or a class or a module or a component?
In this library if I call a function from a component and this function need to access a variable in the caller, will it be possible to do?
If it's just a set of one off helper functions the easiest way is create an #Injectable service with your helper methods then inject that into any component that requires them. You can provide public vars as well so they're accessible in your html.
#Injectable()
export class Helpers {
helper1() { return "hello"; }
helper2(x) { return x + 1 }
}
#Component({
providers: [Helpers],
template: "<div>{{helper1()}}</div>" // will display 'hello'
)}
export class MyComponent {
public helper1: Function = Helpers.helper1;
constructor() {
console.log(Helpers.helper2(5)); // will output '6'
}
}
This works great for a simple set of random utility functions. If you need something more in depth please explain and we can provide alternate solutions.
I think what I am asking for is not possible OOB, but I want to confirm.
We are in a process of upgrading to ES6 (using Babel). Project is a web-site, using AMD (requirejs). I would like to turn a utility module (foolib) into ES6, but consume it from either ES6 (using import) or existing ES5/AMD module.
// foolib.es6
export { // as expected, this doesn't work
method1: function () { ... },
value1: 123.456
};
// consumer1.es6
import foolib from "foolib";
// consumer2.js
define(["foolib"], function (foolib) {});
I understand that the solution is to change foolib.es6 as follows:
export function method1() { ... };
export let value1 = 123.456;
However in reality number of entries returned from foolib is ridiculous. So I was hoping there is a way to export existing object literal without rewriting every line.
Furthermore, I realize that this is most likely impossible, due to the differences between AMD import (using define) and import mechanism (later works with exports object that has values hanging off of it, including default value, while former expects a single value to be returned).
One possible solution that I think might work is to export my object as default from foolib.es6, and then tweak requirejs default loader to inspect imported value for being an esModule and return default value: value && value.__esModule && value.default || value. Should this work? (I'm still hoping there is an easier solution).
The syntax you are using to export the object is invalid because you are not giving the object a name, so it cannot be a named export, and you are not specifying that it is the default export, so it cannot be the default export. Change it to be the default export:
// foolib.es6
export default {
method1: function () {},
value1: 123.456
}
// consumer.es6
import foolib from "foolib";
console.log(foolib.value) //=> 123.456
You can use the babel-plugin-add-module-exports Babel plugin to reinstate a default export as the value of module.exports in Node-land.
And as you discovered, make sure you include this plugin before any other -modules- plugins, for example transform-es2015-modules-amd.
This might be late but alternatively you can use the named export as well which is a little different from the default approach that #sdgluck mentioned.
const method1 = function () {};
const value1 = 123.456;
export { method1, value1 };
I like this approach because you can import them directly like
import { method1, value1 } from 'foolib';
without reaching out to the default variable.
I am making a project where I need several modules which are imported into one main module. I have decided to move the interaction to a single Tkinter window. Instead of using input() I use tkinter.Entry(), for example. I have functions for each step of the interaction.
When I get past the last function of the first module, the configured button has a command to go to a function in the second module. I get an error saying that the command is not defined.
I seem unable to import the configured button variable into the next module, and anything else I tried gave no result. It simply doesn't go to the next module after the first module is done.
I have made the main Tkinter window in the main module and have it that it will mainloop after importing the other modules. Shouldn't the function I want to call upon be defined? How can I get from one function to the next if the latter is in a separate module?
Here is a minimal example:
main_script.py
import tkinter
mainwindow = tkinter.Tk()
# here i set the window to a certain size etc.
import mod1
import mod2
mainwindow.mainloop()
mod1.py
import tkinter
def button1():
label.destroy()
button1.destroy()
button2.config(text = "continue", command = func2)
def button2():
label.destroy()
button1.destroy()
button2.config(text = "continue", command = func2)
label = tkinter.Label(text = "example label")
button1 = tkinter.Button(text = "button1", command = button1)
button2 = tkinter.Button(text = "button2", command = button2)
label.pack()
button1.pack()
button2.pack()
mod2.py
def func2():
button2.destroy()
print ("haha it works...")
Importing a module has no effect on what the module you import can see. If you want to use mod1 contents in mod2 and mod2 contents in mod1, you need to have them import each other and refer to each other's contents with the appropriate module:
# mod1
import mod2
...
button2.config(text = "continue", command = mod2.func2)
# mod2
import mod1
def func2():
mod1.button2.destroy()
Circular imports cause nasty initialization order issues, though, so imports like this are a bad idea. When dividing your code into modules, try to do so in such a way that import loops like this aren't necessary.