YANG 1.1: RFC7950 Modules and Submodules backward compatibility - rfc

I'm quite new in YANG. While reading Module and Submodule section, I confused about the access right of submodule.
RFC7950#section-5.1 indicated that:
"A submodule can reference any definition in the module it belongs to and in all submodules included by the module"
but it also indicated:
"For a module or submodule to reference definitions in an external module, the external module MUST be imported"
So my understand is that if A have two submodules B and C, C import D.
Then B could access to any definition in C but NOT definitions in D.
Am I correct?
If yes, Could B access definitions that using D in C?
Thank you in advance

If A have two submodules B and C, C import D. Then B could access to any definition in C but NOT definitions in D. Am I correct?
Yes, you are correct. Submodules still need their own imports. This is to ensure that each file (note that I did not say "module") has a well defined prefix mapping. Prefixes are not inherited in YANG.
Could B access definitions that using D in C?
B and C see all definitions that are defined in A, B, and C. When you import D in C, you are not defining any new definitions, you are making it possible to re-use already defined ones. B would need an explicit import for D in order to see its definitions.
The RFC is meant to be read a whole. I suggest you also read the section for the "import" statement and then the section for the "include" statement in addition to the one you stated. Those are the sections that define the actual mechanism behind importing and including. The section for "belongs-to" is also relevant.
Import:
The "import" statement makes definitions from one module available
inside another module or submodule. The argument is the name of the
module to import, and the statement is followed by a block of
substatements that holds detailed import information. When a module
is imported, the importing module may:
o use any grouping and typedef defined at the top level in the
imported module or its submodules.
o use any extension, feature, and identity defined in the imported
module or its submodules.
o use any node in the imported module's schema tree in "must",
"path", and "when" statements, or as the target node in "augment"
and "deviation" statements.
RFC7950, Section 7.1.5
Include:
The "include" statement is used to make content from a submodule
available to that submodule's parent module. The argument is an
identifier that is the name of the submodule to include. Modules are
only allowed to include submodules that belong to that module, as
defined by the "belongs-to" statement (see Section 7.2.2).
When a module includes a submodule, it incorporates the contents of
the submodule into the node hierarchy of the module.
RFC7950, Section 7.1.6
Belongs-to:
The "belongs-to" statement specifies the module to which the
submodule belongs. The argument is an identifier that is the name of
the module.
A submodule MUST only be included by either the module to which it
belongs or another submodule that belongs to that module.
The mandatory "prefix" substatement assigns a prefix for the module
to which the submodule belongs. All definitions in the module that
the submodule belongs to and all its submodules can be accessed by
using the prefix.
RFC7950, Secction 7.2.2
Note that the "include" statement's scoping rules are different in YANG 1 (RFC6020). What I described only applies to YANG 1.1. In YANG 1, submodules need to explicitly include another submodule to see its definitions and a submodule cannot see definitions defined in the including module.
You can also read more here.

Related

Separating operator definitions for a class to other files and using them

I have 4 files all in the same directory: main.rakumod, infix_ops.rakumod, prefix_ops.rakumod and script.raku:
main module has a class definition (class A)
*_ops modules have some operator routine definitions to write, e.g., $a1 + $a2 in an overloaded way.
script.raku tries to instantaniate A object(s) and use those user-defined operators.
Why 3 files not 1? Since class definition might be long and separating overloaded operator definitions in files seemed like a good idea for writing tidier code (easier to manage).
e.g.,
# main.rakumod
class A {
has $.x is rw;
}
# prefix_ops.rakumod
use lib ".";
use main;
multi prefix:<++>(A:D $obj) {
++$obj.x;
$obj;
}
and similar routines in infix_ops.rakumod. Now, in script.raku, my aim is to import main module only and see the overloaded operators also available:
# script.raku
use lib ".";
use main;
my $a = A.new(x => -1);
++$a;
but it naturally doesn't see ++ multi for A objects because main.rakumod doesn't know the *_ops.rakumod files as it stands. Is there a way I can achieve this? If I use prefix_ops in main.rakumod, it says 'use lib' may not be pre-compiled perhaps because of circular dependentness
it says 'use lib' may not be pre-compiled
The word "may" is ambiguous. Actually it cannot be precompiled.
The message would be better if it said something to the effect of "Don't put use lib in a module."
This has now been fixed per #codesections++'s comment below.
perhaps because of circular dependentness
No. use lib can only be used by the main program file, the one directly run by Rakudo.
Is there a way I can achieve this?
Here's one way.
We introduce a new file that's used by the other packages to eliminate the circularity. So now we have four files (I've rationalized the naming to stick to A or variants of it for the packages that contribute to the type A):
A-sawn.rakumod that's a role or class or similar:
unit role A-sawn;
Other packages that are to be separated out into their own files use the new "sawn" package and does or is it as appropriate:
use A-sawn;
unit class A-Ops does A-sawn;
multi prefix:<++>(A-sawn:D $obj) is export { ++($obj.x) }
multi postfix:<++>(A-sawn:D $obj) is export { ($obj.x)++ }
The A.rakumod file for the A type does the same thing. It also uses whatever other packages are to be pulled into the same A namespace; this will import symbols from it according to Raku's standard importing rules. And then relevant symbols are explicitly exported:
use A-sawn;
use A-Ops;
sub EXPORT { Map.new: OUTER:: .grep: /'fix:<'/ }
unit class A does A-sawn;
has $.x is rw;
Finally, with this setup in place, the main program can just use A;:
use lib '.';
use A;
my $a = A.new(x => -1);
say $a++; # A.new(x => -1)
say ++$a; # A.new(x => 1)
say ++$a; # A.new(x => 2)
The two main things here are:
Introducing an (empty) A-sawn package
This type eliminates circularity using the technique shown in #codesection's answer to Best Way to Resolve Circular Module Loading.
Raku culture has a fun generic term/meme for techniques that cut through circular problems: "circular saws". So I've used a -sawn suffix of the "sawn" typename as a convention when using this technique.[1]
Importing symbols into a package and then re-exporting them
This is done via sub EXPORT { Map.new: ... }.[2] See the doc for sub EXPORT.
The Map must contain a list of symbols (Pairs). For this case I've grepped through keys from the OUTER:: pseudopackage that refers to the symbol table of the lexical scope immediately outside the sub EXPORT the OUTER:: appears in. This is of course the lexical scope into which some symbols (for operators) have just been imported by the use Ops; statement. I then grep that symbol table for keys containing fix:<; this will catch all symbol keys with that string in their name (so infix:<..., prefix:<... etc.). Alter this code as needed to suit your needs.[3]
Footnotes
[1] As things stands this technique means coming up with a new name that's different from the one used by the consumer of the new type, one that won't conflict with any other packages. This suggests a suffix. I think -sawn is a reasonable choice for an unusual and distinctive and mnemonic suffix. That said, I imagine someone will eventually package this process up into a new language construct that does the work behind the scenes, generating the name and automating away the manual changes one has to make to packages with the shown technique.
[2] A critically important point is that, if a sub EXPORT is to do what you want, it must be placed outside the package definition to which it applies. And that in turn means it must be before a unit package declaration. And that in turn means any use statement relied on by that sub EXPORT must appear within the same or outer lexical scope. (This is explained in the doc but I think it bears summarizing here to try head off much head scratching because there's no error message if it's in the wrong place.)
[3] As with the circularity saw aspect discussed in footnote 1, I imagine someone will also eventually package up this import-and-export mechanism into a new construct, or, perhaps even better, an enhancement of Raku's built in use statement.
Hi #hanselmann here is how I would write this (in 3 files / same dir):
Define my class(es):
# MyClass.rakumod
unit module MyClass;
class A is export {
has $.x is rw;
}
Define my operators:
# Prefix_Ops.rakumod
unit module Prefix_Ops;
use MyClass;
multi prefix:<++>(A:D $obj) is export {
++$obj.x;
$obj;
}
Run my code:
# script.raku
use lib ".";
use MyClass;
use Prefix_Ops;
my $a = A.new(x => -1);
++$a;
say $a.x; #0
Taking my cue from the Module docs there are a couple of things I am doing different:
Avoiding the use of main (or Main, or MAIN) --- I am wary that MAIN is a reserved name and just want to keep clear of engaging any of that (cool) machinery
Bringing in the unit module declaration at the top of each 'rakumod' file ... it may be possible to use bare files in Raku ... but I have never tried this and would say that it is not obvious from the docs that it is even possible, or supported
Now since I wanted this to work first time you will note that I use the same file name and module name ... again it may be possible to do that differently (multiple modules in one file and so on) ... but I have not tried that either
Using the 'is export' trait where I want my script to be able to use these definitions ... as you will know from close study of the docs ;-) is that each module has it's own namespace (the "stash") and we need export to shove the exported definitions into the namespace of the script
As #raiph mentions you only need the script to define the module library location
Since you want your prefix multi to "know" about class A then you also need to use MyClass in the Prefix_Ops module
Anyway, all-in-all, I think that the raku module system exemplifies the unique combination of "easy things easy and hard thinks doable" ... all I had to do with your code (which was very close) was tweak a few filenames and sprinkle in some concise concepts like 'unit module' and 'is export' and it really does not look much different since raku keeps all the import/export machinery under the surface like the swan gliding over the river...

Can I get the original target name from an alias target?

If I create an alias target in CMake like
add_library(my::foo ALIAS my_foo)
is there any way to query the name of the underlying target name from the alias target?
My use case:
A shared C++ codebase with several independent modules. The root folder of this codebase contains a CMakeList.txt to be added via add_subdirectory to the project using it. According to our convention e.g. my_foo will always be located in a subfolder named my_foo. Furthermore, my_foo will be exported as alias target my::foo and used as such in the project. Note that my_foo is always an INTERFACE target, so I cannot set any custom properties on it.
We use conan to manage third party library dependencies. All modules that have such dependencies contain a conanfile.txt
For convenience I want to write a function (located in the shared codebase's root CMakeList) that takes a list of module targets the project wants to use and scans all of them for conanfiles and sets up the dependencies for those used. I want to be able to pass my::foo as argument to that function but derive my_foo from that argument inside the function to get the corresponding folder name to scan for the conanfile
Any other suggestions that solve the problem according to my use case are welcome as well!
An alias target has a special property, where it store name of the original target: ALIASED_TARGET.
get_target_property(my_foo_original my::foo ALIASED_TARGET)
message(STATUS "Alias my::foo refers to the target ${my_foo_original}")

What is the proper way to reference a sibling module such as Diesel's generated schema? [duplicate]

This question already has an answer here:
How do I import from a sibling module?
(1 answer)
Closed 2 years ago.
I'm building a web service that uses Diesel to access a MySQL database. Everything is setup correctly and Diesel is generating the schema.rs file with content that reflects my database schema:
table! {
user (id) {
// ...
}
}
I created a store.rs file that resides next to main.rs. If my understanding of modules is correct, any code I put in the store.rs file, will belong to a module named store that is a child of the crate module. My intention is to put all the code that deals with database stuff in the store module. However, I can't seem to be able to use the stuff from the schema module in my store module to start doing some querying using the Diesel APIs.
I tried:
use schema;
use crate::schema;
use super::schema;
use super::schema::user;
Nothing works. The compiler always says that it cannot resolve one piece of the path or another.
What is the proper way to reference a sibling module in Rust?
In your main.rs, make sure you're setting diesel for #[macro_use] and importing the schema mod.
#[macro_use]
extern crate diesel;
mod schema;
In store.rs, you should be able to use the schema as you see fit.
use crate::schema::user;
I hope this would help.
in store.rs
use crate::schema::*;
// … any other diesel related code you want to put here
in main.rs
pub mod schema;
mod store;

What is the purpose of the TARGET_NAME generator expression?

In the CMake documentation describing generator expressions there is this paragraph:
$<TARGET_NAME:...>
Marks ... as being the name of a target. This is required if exporting targets to multiple dependent export sets. The ... must be a literal name of a target- it may not contain generator expressions.
I am trying to understand the highlighted part.
First I want to see if I understand correctly the notion of dependent export sets. If target B depends on target A and if export set EXP_A contains target A and export set EXP_B contains target B, then the export set EXP_B is dependent on the export set EXP_A. Is this correct?
Why is $<TARGET_NAME:...> "required if exporting targets to multiple dependent export sets"?
I'm not sure what they mean by "multiple dependent export sets". I looked at their test suite and couldn't find anything like that. It's confusing to me, too.
However, I can give you an example where $<TARGET_NAME:...> actually does something. Consider:
cmake_minimum_required(VERSION 3.20)
project(test)
add_library(define_a INTERFACE)
target_compile_definitions(define_a INTERFACE A)
add_library(define_a_tgt INTERFACE)
target_compile_definitions(define_a_tgt INTERFACE "A_TGT=\"$<TARGET_NAME:define_a>\"")
include(GNUInstallDirs)
install(TARGETS define_a define_a_tgt EXPORT test)
install(
EXPORT test
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/test
FILE test-config.cmake
NAMESPACE test::
)
Here, we have two silly INTERFACE libraries. The first, define_a, simply propagates -DA to the target linking to it. The second, define_a_tgt adds a definition of A_TGT such that it is equal to the string containing the name of the target define_a.
In the build interface, this will expand to simply define_a, but after exporting it, CMake will replace $<TARGET_NAME:define_a> with test::define_a (on account of the NAMESPACE argument to install(EXPORT)).
This is a bit contrived, but it does show an instance where CMake is not already aware that a target is being named (it transforms target_link_libraries targets automatically, without this genex). Another instance is inside other generator expressions (even in target_link_libraries).

Including a module more than once

Suppose I have a module which defines some basic constants such as
integer, parameter :: i8 = selected_int_kind(8)
If I include this in my main program and I also include a module which does some other things (call this module functions) but functions also uses constants, then am I essentially including constants twice in my main program?
If so, is this bad? Can it be dangerous at all to include a module too many times in a program?
No, it is fine to do this. All you are doing with the use statement is providing access to the variables and functions defined in your module via use association. It is not like declaring variables each time they are use'd (they are in fact redeclared however).
The only thing to be wary of are circular dependencies, where module A uses module B and module B uses module A. This is not allowed.
Edit: From Metcalf et al. Fortran 95/2003 explained, pg. 72:
A module may contain use statements that access other modules. It must not access itself directly or indirectly through a chain of use statements, for example a accessing b and b accessing a.
Whilst this quote doesn't directly answer your question, it reiterates that really the only thing you can't do is have a circular dependency. So the following is perfectly valid:
module one_def
implicit none
integer, parameter :: one=1
end module one_def
module two_def
use one_def, only : one
implicit none
integer, parameter :: two=one+one
end module two_def
program test
use one_def, only : one
use two_def, only : two
implicit none
print*, two == one+one ! This prints .True.
end program