I have two files:
Main.kt:
package A
fun gg1() = "hello"
Main2.kt:
package B
import A.gg1
fun gg2() = gg1()
Trying to compile the code:
iv#LAPTOP:~$ tree .
.
├── A
│ └── Main.kt
└── B
└── Main2.kt
2 directories, 2 files
iv#LAPTOP:~$ kotlinc B/Main2.kt
B/Main2.kt:3:8: error: unresolved reference: A
import A.gg1
^
B/Main2.kt:5:13: error: unresolved reference: gg1
fun gg2() = gg1()
^
iv#LAPTOP:~$
Why do i get this error and how to fix it ?
You're only passing B/Main2.kt to kotlinc. You need to pass the other file too if you want the compiler to be aware of its existence.
Imports don't work as file/path references: the import A.gg1 doesn't tell the compiler to look for A/Main.kt (how would it know the file name?). There is no technical relation between the package names and the paths of the files, just a convenient convention.
In fact, imports are mostly syntax sugar to avoid using fully qualified names within the code (so the code itself looks a bit simpler), but they are not necessary per se, and you could just use declarations without imports if you wanted to (except in some specific cases).
Maybe this related question could shed some light too:
How does import find the file path in Kotlin?
Related
I'm writing my own compiler and I'm struggling to implement a module system.
Can someone guide me, how should this be done? how other languages tackle this?
Also I'm trying to avoid what c and c++ do (header files).
I do like the module system in Go/Golang though.
I don't know if this is relevant, but I'm using LLVM (maybe there's a magic way to import symbols).
my initial approach:
read and parse the entry point source file ie. main.mylang.
go through the imports of main.mylang
for each import: read, parse and resolve it's imports
...
this leads to a tree structure:
main.mylang: import1.mylang, import2.mylang, import3.mylang
import1.mylang: import4.mylang, import5.mylang
import2.mylang: import6.mylang
... etc.
then I would traverse each node and copy it's symbols (functions, global variables, etc.) to the parent node's symbol table. if a parent node is null, it's an entry point file and the compiler can start output object files.
why do I think that this is bad?
it's very slow, even when compiling 3-5 source files
it's easy to cause name collisions
you have to import the entire symbol table, because the imported file's exported symbols depend on the internal ones.
for example: imagine an exported function that modifies an internal global variable
Thanks in advance
I think your approach is really good. Compile time speed is not that important, usability is. To prevent name collisions you can use some kind of module-namespace (importname.foo() instead of just foo()) and whenever foo does not exist allow both methods. Alternatively you could insert a placeholder in the parents symbol table and whenever the user uses that name you throw a compile time error (something like ambiguous symbol).
that would look like this:
main.mylang
import module1
import module2
int main() {}
module1.mylang
import module2
void foo() {}
void bar() {}
module2.mylang
import module1
void bar() {}
void fun() {}
After finding loops, the tree would look like this:
main
├──module1
│ └──module2
└──module2
└──module1
And a graph like this:
main
├─>main()
├─>foo() (module1)
├─>bar() (defined twice, throw error when used)
├─>fun() (module2)
├─>module1<───────────┐
│ ├─>foo() (module1) │
│ └─>bar() (module1) │
└─>import2<───────────┘
├─>bar() (module2)
└─>fun() (module2)
I don't know much about llvm, but I am pretty sure normal tables are not enough to archive this. You will at least need nested tables if not even a graph like structure like I described. Also this is not possible with classical C/C++ architecture, except if you use unique identifiers as symbols and don't let the user know (like c++ function overloading). For example you could call one function __import1_bar and the other __import2_bar and whenever the user uses bar() you look up in this graph which one he wants to call. In the main function using import1.bar() will lead you to __import1_bar (follow the graph) and import2.bar() or import1.import2.bar() will lead you to __import2_bar.
Good Luck figuring that out. But it is certainly a interesting problem.
I just added immutable.js as a dependency to my project. I added
node_modules/immutable/dist/immutable.js.flow
to my .flowconfig.
The problem is that immutable exports an Iterable type, which is also a global type used in many other libraries that are in node_modules/, such as fbjs and react-native. For example one of the errors below.
node_modules/fbjs/lib/countDistinct.js.flow:22
22: function countDistinct<T1, T2>(iter: Iterable<T1>, selector: (item: T1) => T2): number {
^^^^^^^^^^^^ type application of identifier `Iterable`. Too few type arguments. Expected at least 2
32: declare class Iterable<K, V> extends _ImmutableIterable<K, V, typeof KeyedIterable, typeof IndexedIterable, typeof SetIterable> {}
^^^^ See type parameters of definition here. See lib: flow/immutable.js:32
In order to fix this I copied immutable.js.flow to my project and removed the .flowconfig line that includes it. In my copied file I rename Iterable to WhateverIterable and the errors are gone.
What is the best way to fix this thing without having to manually edit the immutable definitions?
The main problem is that node_modules/immutable/dist/immutable.js.flow is not written to be a library definition, so using it as one can cause errors.
What is immutable.js.flow
The docs refer to these files as declaration files. immutable.js.flow sits next to a file named immutable.js. Whenever Flow is asked to require immutable.js, it will resolve to immutable.js.flow instead. You can test this with the flow find-module command, which shows which file Flow resolves to when foo.js imports immutable:
$ flow find-module immutable foo.js
/Users/glevi/test/immutable/node_modules/immutable/dist/immutable.js.flow
Declaration files are written a little differently than libdefs. Library definitions declare a bunch of global things. They declare which variables, functions, types, classes, modules, etc are available globally, and declare the types of these things. Declaration files declare only the type of the module that they are shadowing.
A libdef for immutablejs would look like
declare module 'immutable' {
declare class Iterable<K,V> { ... }
...
}
while immutable.js.flow might look like
declare export class Iterable<K,V> { ... }
What should you do
In theory, you should not need to add node_modules/immutable/dist/immutable.js.flow to your .flowconfig. Flow should automatically use it whenever your code imports immutable.
If there is a problem with the immutable.js.flow that immutable ships with, then the best thing to do is to open a pull request or issue against immutable.js.flow or to submit a libdef to flow-typed.
A quick search shows someone working on a immutable libdef, so that might help too!
I'm trying to create a crate that has a library and one or more binaries. I've looked at Rust package with both a library and a binary? and the Rust book section on crates and modules but am still running into errors when I try and compile.
I've included the relevant sections of each file (I think).
../cargo.toml:
[package]
name = "plotmote"
version = "0.1.0"
authors = ["Camden Narzt <my#nice.email>"]
[lib]
name = "lib_plotMote"
path = "src/lib.rs"
[[bin]]
name = "plotMote"
path = "src/main.rs"
lib.rs:
pub mod lib_plotMote;
lib_plotMote/mod.rs:
pub mod LogstreamProcessor;
lib_plotMote/LogstreamProcessor.rs:
pub struct LogstreamProcessor {
main.rs:
extern crate lib_plotMote;
use lib_plotMote::LogStreamProcessor;
error:
cargo build
Compiling plotmote v0.1.0 (file:///Users/camdennarzt/Developer/Rust/plotmote)
main.rs:6:5: 6:37 error: unresolved import `lib_plotMote::LogStreamProcessor`. There is no `LogStreamProcessor` in `lib_plotMote` [E0432]
This should work:
use lib_plotMote::lib_plotMote::LogStreamProcessor;
The first lib_plotMote comes from extern crate, and the second one comes from the module you have defined in the library crate:
pub mod lib_plotMote;
Therefore, the library crate contains one module which, coincidentally, has the same name as the crate itself.
Also, as #starblue has noticed, you have case mismatch in the declaration site of the structure (LogstreamProcessor) and its use site (LogStreamProcessor). This should also be fixed.
As as side note, I suggest you to follow the idiomatic naming convention and avoid camelCase in module/crate names.
I have two files :
json.rs in which I call Builder, a struct defined in builder.rs
builder.rs in which I call Json, a struct defined in json.rs
As you can see there is a circular dependency between these two modules. It seems like sometimes Rust supports circular dependencies, but for this case, the compiler throws errors:
src/json/mod.rs:1:25: 1:31 error: unresolved import (maybe you meant `ToJson::*`?)
src/json/mod.rs:1 pub use self::to_json::{ToJson};
^~~~~~
src/json/builder.rs:2:18: 2:22 error: unresolved import (maybe you meant `Json::*`?)
src/json/builder.rs:2 use json::json::{Json, JsonEvent, Array, Object}; //commenting this line solve the dependency error
[...]
The code is here in the branch json_mod. I tried to reproduce the problem in fewer lines of code, but the circular dependencies I created compiled correctly.
After the debugging, something like 400 errors are left — this is normal as I am in the process of a huge code refactoring (splitting one file of ~= 4000 line file into many files) and I still have a lot of work to do before making it work.
Edit: Glorious news, the bug mentioned below is fixed! It's fixed in Rust 1.4 or later.
Glob imports (use foo::*) have a known bug where they are incompatible with cyclic imports. I would try removing the glob imports in both affected modules.
In the setup I'm working the variable $var1 is declared in several places. However I'm not sure which line is last applied. The structure is as follows.
The puppet module, module1, contains a vars.pp class which is inherited by its init.pp manifest. In the vars.pp manifest var1 is declared as "value-vars".
#vars.pp
$var1 = "value-vars"
This module is applied to any node that matches a certain regex which is defined in the nodes.pp.
#nodes.pp
node "/nodepattern/" inherits base {
require module1
}
nodes.pp inherits from base.pp which declares var1 as "value-base".
#base.pp
$var1 = "value-base"
Now when the module is applied to a certain node, what value would var1 contain?
Is it "value-vars" because node block is applied before the class?
UPDATE
├── puppet3
│ ├──**manifests**
│ │ └───**nodes**
│ │ └──base.pp (node "base", $var1 = "value-base")
│ ├──nodes.pp (various nodes inheriting base node, contains module1 node)
│ ├──**modules**
│ │ ├──**module1**
│ │ │ ├──**manifests**
│ │ ├──vars.pp (class "vars", $var1 = "value-vars")
│ │ ├──init.pp (class "module1", inherits vars class)
I sense some confusion here. A manifest cannot "inherit" another manifest. What's worse - from Puppet 4.0, a manifest file will not even be able to import another one.
This leaves scarce options to declare globally scoped variables. You should avoid declaring the same variable globally in different .pp files anyway, because any compilation that imports both files will fail!
Structure that works like "if this node includes module A, use value X for variable N" is tricky with Puppet. Manifests work best if there is one central piece of information that you can rely on, e.g.
node <long-cloud-instance-name-here> {
$uses_app_foo = true
$is_master_server = false
include my_cloud_app
}
Both the decision to include module A and the assignment of X to N should then be based on those node scope variables.
This pattern gets old for large numbers of nodes. It is therefor advisable to devise a Hiera hierarchy that helps you define your node data with less redundancy.
Update
Seeing as you are using classes apparently, here are the additional rules that should make things clearer:
a variable that is declared in the local scope (class or define body) hides variables from wider scopes that share its name
a variable that is declared in the node block hides a global variables with the same name
Evaluation order does not come into play. The scoping rules always apply. Multiple assignments on the same scope are forbidden and lead to a compiler error. As you are not facing that scenario, the above rules do apply.
$foo = 'global'
# $foo == 'global'
node default {
$foo = 'node'
include bar
# $foo == 'node'
}
class bar {
$foo = 'class'
# $foo == 'class'
include baz
}
class baz {
# foo == 'node' (!)
}