Comparison based default value for a leaf in a same list in yang model - ietf-netmod-yang

I would like to assign different default value to a leaf according to type of key the list entries take. as an example, although not correct:
typedef type-id {
type enumeration {
enum a{
value 1;
}
enum b{
value 2;
}
enum c{
value 3;
}
}
}
list domain {
key id;
leaf id {
type type-id;
}
leaf my-leaf {
when "../id = 'a'"{
default 10;
}
when "../id = 'b'"{
default 20;
}
when "../id = 'c'"{
default 20;
}
}
}
So let say there are two entries for the list and the corresponding keys are 'a' and 'c'
When I walk through the model I would like to have values as
domain id my-leaf
'a' 10
'c' 30
Which expression is the best solution for this purpose? How can I model such a structure?

Related

How to assign raw value to enum in Dart?

In Swift, you can easily assign raw value to enum, eg:
enum Game: Int {
case lol = 1
case dnf = 2
case dota = 3
}
However, you can't assign raw value to enum in Dart:
enum Game {
lol = 1,
dnf = 2,
dota = 3,
}
It's showed error and you can only use the simplest enum:
enum Game {
lol,
dnf,
dota,
}
It's really let me down.
Any way assign raw value to Dart's enum like Swift?
Dart 2.17 support enhanced enum
enum Game {
lol(1),
dnf(2),
dota(3);
const Game(this.value);
final int value;
}
Use it like:
void main() {
const game = Game.lol;
print(game.value); // 1
}
There's an upcoming feature in Dart known as enhanced enums, and it allows for enum declarations with many of the features known from classes. For example:
enum Game {
lol,
dnf,
dota;
int get intValue => index + 1;
}
The feature is not yet released (and note that several things are not yet working), but experiments with it can be performed with a suitably fresh version of the tools by passing --enable-experiment=enhanced-enums.
The outcome is that an enum value of type Game will have a getter intValue that returns the int values mentioned in the question, so print(myGame.intValue) will print 1, 2, or 3.
You can use enum extensions for example
enum EnumAction { subtract, add }
extension EnumActionExtension on EnumAction {
String get name {
switch (this) {
case EnumAction.add:
return 'add';
case EnumAction.subtract:
return 'subtract';
}
}
}
In your case you would return an int and an int value. Enums also have int values assigned to them by default, their respective index. You could call Game.lol.index and it would return 0.
To get an int value, simply pass an enum to the enumGame function.
enum EnumGame { lol, dnf, dota }
enumGame(EnumGame enumGame) {
switch (enumGame) {
case EnumGame.lol:
return 1;
case EnumGame.dnf:
return 2;
case EnumGame.dota:
return 3;
default:
return -1;
}
}

How can I change the element in an array of struct

I have an array of struct 'Pair' (Data) and I want to change the element in the array if some condition is met. I have followed the documentation https://docs.swift.org/swift-book/LanguageGuide/Methods.html and created a 'setValue' method with mutating
But when I debug the code, I see the value of the pair variable get changed. But the array 'data?.pairs' does not get changed to the new value 'Point(1,2). Can you please tell what am I missing?
public struct Data {
var pairs: [Pair<Point>]
}
var array = data?.pairs ?? []
for index in 0..<array.count {
var pair = data?.pairs[index]
if /* some test */ {
print ("Found match")
pair?.setValue(Point(1,2)) // `pair` is updated, but data?.paris[index] is not updated.
}
}
struct Pair<Value: Comparable>{
var key: Value
var value: Value
init(_ key: Value, _ value: Value) {
self.key = key
self.value = value
}
mutating func setValue(_ value: Value) {
self.value = value
}
}
Pair is a struct, so value semantics apply. This means that here, you made a copy of each item in data.pairs:
var pair = data?.pairs[index]
And you are changing the copies, not the originals.
One way to solve this is to assign the changed copies back to data.pairs:
if /* some test */ {
print ("Found match")
pair?.setValue(Point(1,2))
data?.pairs[index] = pair // here!
}
Or, don't make a copy in the first place:
if /* some test */ {
print ("Found match")
data?.pairs[index].setValue(Point(1,2))
}
Or, make Pair a class, so reference semantics apply, and you won't be making copies.
As we know, arrays and structs in Swift are value types, so at the moment
var pair = data?.pairs[index]
the pair is a copy of an array item value, and has no relation to the original array.

Using Enum in if-else in Swift

I have the following for loops with if-else condition. However, it is not quite intituitve for others to read the code at a first glance. therefore I am thinking to use Enum here.
for row in 0..<result.count {
for column in 0..<result[row].count {
if column == 0 {
// add hotels here
} else if column == 1 {
// add motels here
}
}
}
I am trying to use the following enum, but I am confused how to put into if-else condition.
enum ResortColumn {
case hotel
case motel
}
If you want to compare your enum type to an integer, you need to declare it an Int and compare its rawValue.
enum ResortColumn: Int {
case hotel
case motel
}
if column == ResultColumn.hotel.rawValue { // etc.
See the second "enum Planet" example on this page, and read the rest for a full understanding of Swift enums:
https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html
enum ResortColumn: Int {
case hotel
case motel
}
for row in 0 ..< result.count {
for column in 0 ..< result[row].count {
let resortColumn = ResortColumn(rawValue: column)
switch resortColumn {
case .hotel:
// add hotels here
case .motel:
// add motels here
}
}
}
This is the best what I can come up with the context you gave. In this case, it does really matter what is behind the result variable

How to count the number of dimensions in Swift array [duplicate]

Suppose I have some function that I want to populate my data structure using a multi-dimensional array (e.g. a Tensor class):
class Tensor {
init<A>(array:A) { /* ... */ }
}
while I could add in a shape parameter, I would prefer to automatically calculate the dimensions from the array itself. If you know apriori the dimensions, it's trivial to read it off:
let d1 = array.count
let d2 = array[0].count
However, it's less clear how to do it for an N-dimensional array. I was thinking there might be a way to do it by extending the Array class:
extension Int {
func numberOfDims() -> Int {
return 0
}
}
extension Array {
func numberOfDims() -> Int {
return 1+Element.self.numberOfDims()
}
}
Unfortunately, this won't (rightfully so) compile, as numberOfDims isn't defined for most types. However, I'm don't see any way of constraining Element, as Arrays-of-Arrays make things complicated.
I was hoping someone else might have some insight into how to solve this problem (or explain why this is impossible).
If you're looking to get the depth of a nested array (Swift's standard library doesn't technically provide you with multi-dimensional arrays, only jagged arrays) – then, as shown in this Q&A, you can use a 'dummy protocol' and typecasting.
protocol _Array {
var nestingDepth: Int { get }
}
extension Array : _Array {
var nestingDepth: Int {
return 1 + ((first as? _Array)?.nestingDepth ?? 0)
}
}
let a = [1, 2, 3]
print(a.nestingDepth) // 1
let b = [[1], [2, 3], [4]]
print(b.nestingDepth) // 2
let c = [[[1], [2]], [[3]], [[4], [5]]]
print(c.nestingDepth) // 3
(I believe this approach would've still worked when you had originally posted the question)
In Swift 3, this can also be achieved without a dummy protocol, but instead by casting to [Any]. However, as noted in the linked Q&A, this is inefficient as it requires traversing the entire array in order to box each element in an existential container.
Also note that this implementation assumes that you're calling it on a homogenous nested array. As Paul notes, it won't give a correct answer for [[[1], 2], 3].
If this needs to be accounted for, you could write a recursive method which will iterate through each of the nested arrays and returning the minimum depth of the nesting.
protocol _Array {
func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int
}
extension Array : _Array {
func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int {
// for an empty array, the minimum depth is the current depth, as we know
// that _nestingDepth is called where currentDepth <= minimumDepth.
guard !isEmpty else { return currentDepth }
var minimumDepth = minimumDepth
for element in self {
// if current depth has exceeded minimum depth, then return the minimum.
// this allows for the short-circuiting of the function.
if let minimumDepth = minimumDepth, currentDepth >= minimumDepth {
return minimumDepth
}
// if element isn't an array, then return the current depth as the new minimum,
// given that currentDepth < minimumDepth.
guard let element = element as? _Array else { return currentDepth }
// get the new minimum depth from the next nesting,
// and incrementing the current depth.
minimumDepth = element._nestingDepth(minimumDepth: minimumDepth,
currentDepth: currentDepth + 1)
}
// the force unwrap is safe, as we know array is non-empty, therefore minimumDepth
// has been assigned at least once.
return minimumDepth!
}
var nestingDepth: Int {
return _nestingDepth(minimumDepth: nil, currentDepth: 1)
}
}
let a = [1, 2, 3]
print(a.nestingDepth) // 1
let b = [[1], [2], [3]]
print(b.nestingDepth) // 2
let c = [[[1], [2]], [[3]], [[5], [6]]]
print(c.nestingDepth) // 3
let d: [Any] = [ [[1], [2], [[3]] ], [[4]], [5] ]
print(d.nestingDepth) // 2 (the minimum depth is at element [5])
Great question that sent me off on a goose chase!
To be clear: I’m talking below about the approach of using the outermost array’s generic type parameter to compute the number of dimensions. As Tyrelidrel shows, you can recursively examine the runtime type of the first element — although this approach gives nonsensical answers for heterogenous arrays like [[[1], 2], 3].
Type-based dispatch can’t work
As you note, your code as written doesn’t work because numberOfDims is not defined for all types. But is there a workaround? Does this direction lead somewhere?
No, it’s a dead end. The reason is that extension methods are statically dispatched for non-class types, as the following snippet demonstrates:
extension CollectionType {
func identify() {
print("I am a collection of some kind")
}
func greetAndIdentify() {
print("Hello!")
identify()
}
}
extension Array {
func identify() {
print("I am an array")
}
}
[1,2,3].identify() // prints "I am an array"
[1,2,3].greetAndIdentify() // prints "Hello!" and "I am a collection of some kind"
Even if Swift allowed you to extend Any (and it doesn’t), Element.self.numberOfDims() would always call the Any implementation of numberOfDims() even if the runtime type of Element.self were an Array.
This crushing static dispatch limitation means that even this promising-looking approach fails (it compiles, but always returns 1):
extension CollectionType {
var numberOfDims: Int {
return self.dynamicType.numberOfDims
}
static var numberOfDims: Int {
return 1
}
}
extension CollectionType where Generator.Element: CollectionType {
static var numberOfDims: Int {
return 1 + Generator.Element.numberOfDims
}
}
[[1],[2],[3]].numberOfDims // return 1 ... boooo!
This same constraint also applies to function overloading.
Type inspection can’t work
If there’s a way to make it work, it would be something along these lines, which uses a conditional instead of type-based method dispatch to traverse the nested array types:
extension Array {
var numberOfDims: Int {
return self.dynamicType.numberOfDims
}
static var numberOfDims: Int {
if let nestedArrayType = Generator.Element.self as? Array.Type {
return 1 + nestedArrayType.numberOfDims
} else {
return 1
}
}
}
[[1,2],[2],[3]].numberOfDims
The code above compiles — quite confusingly — because Swift takes Array.Type to be a shortcut for Array<Element>.Type. That completely defeats the attempt to unwrap.
What’s the workaround? There isn’t one. This approach can’t work because we need to say “if Element is some kind of Array,” but as far as I know, there’s no way in Swift to say “array of anything,” or “just the Array type regardless of Element.”
Everywhere you mention the Array type, its generic type parameter must be materialized to a concrete type or a protocol at compile time.
Cheating can work
What about reflection, then? There is a way. Not a nice way, but there is a way. Swift’s Mirror is currently not powerful enough to tell us what the element type is, but there is another reflection method that is powerful enough: converting the type to a string.
private let arrayPat = try! NSRegularExpression(pattern: "Array<", options: [])
extension Array {
var numberOfDims: Int {
let typeName = "\(self.dynamicType)"
return arrayPat.numberOfMatchesInString(
typeName, options: [], range: NSMakeRange(0, typeName.characters.count))
}
}
Horrid, evil, brittle, probably not legal in all countries — but it works!
Unfortunately I was not able to do this with a Swift array but you can easily convert a swift array to an NSArray.
extension NSArray {
func numberOfDims() -> Int {
var count = 0
if let x = self.firstObject as? NSArray {
count += x.numberOfDims() + 1
} else {
return 1
}
return count
}
}

Declare dynamically added class properties in TypeScript

I want to assign properties to the instance of a class without knowing the property names, values and types of values in TypeScript. Lets assume we have the following example.ts script:
// This could be a server response and could look totally diffent another time...
const someJson:string = '{ "foo": "bar", "bar": "baz" }'
class MyClass {
someProperty:boolean
constructor( json:string ) {
const parsedJson:any = JSON.parse( json )
Object.keys( parsedJson ).forEach(
( key:string ) => {
this[ key ] = parsedJson[ key ]
}
)
this['someProperty'] = true
}
}
const myInstance = new MyClass( someJson )
// Works fine, logs `true`.
console.log( myInstance.someProperty )
// Error: Property 'foo' does not exist on type 'MyClass'.
console.log( myInstance.foo )
// Error: Property 'bar' does not exist on type 'MyClass'.
console.log( myInstance.bar )
How can I make sure that the TypeScript compiler does not complain of the dynamically added properties but instead handle them as "key": value pairs of any type. I still want tsc to make sure that myInstance.someProperty has to be of type boolean but I want to be able to get myInstance.whatever even if it is not defined without running into compiler errors.
I did not find any documentation that makes this clear to me. Maybe because I'm not a native english speaker. So please keep the answers simple.
Edit:
I remember that there was something like the following but I never got that to work:
interface IMyClass {
[name:string]: any
}
The problem is that you're adding the new properties at runtime and the compiler has no way of knowing that.
If you know the property names in advance then you can do this:
type Json = {
foo: string;
bar: string;
}
...
const myInstance = new MyClass(someJson) as MyClass & Json;
console.log(myInstance.foo) // no error
Edit
If you do not know the properties in advance then you can't do this:
console.log(myInstance.foo);
Because then you know that foo is part of the received json, you'll probably have something like:
let key = getKeySomehow();
console.log(myInstance[key]);
And this should work without an error from the compiler, the only problem with that is that the compiler doesn't know the type for the returned value, and it will be any.
So you can do this:
const myInstance = new MyClass(someJson) as MyClass & { [key: string]: string };
let foo = myInstance["foo"]; // type of foo is string
let someProperty = myInstance["someProperty"]; // type of someProperty is boolean
2nd edit
As you do know the props, but not in the class, you can do:
type ExtendedProperties<T> = { [P in keyof T]: T[P] };
function MyClassFactory<T>(json: string): MyClass & ExtendedProperties<T> {
return new MyClass(json) as MyClass & ExtendedProperties<T>;
}
Then you simply use it like so:
type Json = {
foo: string;
bar: string;
};
const myInstance = MyClassFactory<Json>(someJson);
Note that this will work only on typescript 2.1 and above.
If you want to dynamically add class properties via an object upon instantiation, and type information is available for that object, you can very nicely get full type safety in this way (as long as you don't mind using a static factory method):
class Augmentable {
constructor(augment: any = {}) {
Object.assign(this, augment)
}
static create<T extends typeof Augmentable, U>(this: T, augment?: U) {
return new this(augment) as InstanceType<T> & U
}
}
This is using the (fake) this parameter to infer the constructor type of the class. It then constructs the instance, and casts it to a union of the instance type (using the InstanceType utility type) and the inferred type of the props you passed to the method.
(We could have casted directly to Augmentable & U, however this way allows us to extend the class.)
Examples
Augment basic properties:
const hasIdProp = Augmentable.create({ id: 123 })
hasIdProp.id // number
Augment with methods:
const withAddedMethod = Augmentable.create({
sayHello() {
return 'Hello World!'
}
})
withAddedMethod.sayHello() // Properly typed, with signature and return value
Extend and augment, with this access in method augments:
class Bob extends Augmentable {
name = 'Bob'
override = 'Set from class definition'
checkOverrideFromDefinition() {
return this.override
}
}
interface BobAugment {
whatToSay: string
override: string
sayHelloTo(to: string): void
checkOverrideFromAugment(): string
}
const bobAugment: BobAugment = {
whatToSay: 'hello',
override: 'Set from augment'
sayHelloTo(this: Bob & BobAugment, to: string) {
// Let's combine a class parameter, augment parameter, and a function parameter!
return `${this.name} says '${this.whatToSay}' to ${to}!`
},
checkOverrideFromAugment(this: Bob & BobAugment) {
return this.override
}
}
const bob = Bob.create(bobAugment) // Typed as Bob & BobAugment
bob.sayHelloTo('Alice') // "Bob says 'hello' to Alice!"
// Since extended class constructors always run after parent constructors,
// you cannot override a class-set parameter with an augment, no matter
// from where you are checking it.
bob.checkOverrideFromAugment() // "Set from class definition"
bob.checkOverrideFromDefinition() // "Set from class definition"
Limitations
Augmented properties aren't really part of the class, so you can't extend a class with those augments included. This may be a feature for some use cases where the augments are temporary additions that aren't meant to modify the prototype hierarchy
It is also not easy to add non-augment arguments to .create(), however an easy work-around is to simply utilize the augment functionality to accomplish the same thing you would have with an extra argument.
You can add index signature to your class:
class MyClass {
[index: string]: any; //index signature
someProperty:boolean
constructor( json:string ) {
const parsedJson:any = JSON.parse( json )
Object.keys( parsedJson ).forEach(
( key:string ) => {
this[ key ] = parsedJson[ key ]
}
)
this['someProperty'] = true
}
}