What's the result set operation of extensible constraints in ASN.1 - constraints

I can't figure out which is the result of set operation of extensible constraints in ASN.1, like below:
A ::= INTEGER ( (1..64, ..., 100..128) INTERSECTION (1..32, ..., 33..120) )
B ::= INTEGER ( (1..64, ..., 100..128) UNION (1..32, ..., 33..120) )
C ::= INTEGER (1..64, ..., 100..128) (1..32, ..., 33..120)
What's the resultant constraint of these types?
Any help is appreciated.

The first two definitions are invalid since the ... can only occur at the topmost level, not nested inside multiple parentheses, so A and B are invalid definitions. See ITU-T X.680 clause 50.1 and 50.5.
C is also technically invalid since the value 120 is not within the base range of 1..64 for the "parent type". If you change the 120 to 64, then the effective constraint is as follows:
C ::= INTEGER (1..32, ..., 33..64)
ITU-T X.680 clause 50.10 has the following:
50.10 If a subtype constraint is serially applied to a parent type which is extensible through the application of an extensible constraint, value notation used within it shall not reference values that are not in the extension root of the parent type. The result of the second (serially applied) constraint is defined to be the same as if the constraint had been applied to the parent type without its extension marker and possible extension additions.

Related

Why is Ada not trapping this specified range check?

I am going through the learn.adacore.com tutorial and have hit upon a problem that I am unsure of.
Specifically I understand that Ada is designed to trap attempts to overflow a variable with a specified range definition.
In the case below, the first attempt to do this causes a compiler 'range check failure' which is expected. However the following line doesn't trap it and I am not sure why:
with Ada.Text_IO; use Ada.Text_IO;
procedure Custom_Floating_Types is
type T_Norm is new float range -1.0 .. 1.0;
D : T_Norm := 1.0;
begin
Put_Line("The value of D =" & T_Norm'Image(D));
-- D := D + 1.0; -- This causes a range check failure at run time = completely expected.
Put_Line("The value of D =" & T_Norm'Image(D + 1.0)); -- This doesn't?
end Custom_Floating_Types;
You have a couple of pretty good answers, but I'm going to add another because it's clear that you expect the expression D + 1.0 to raise an exception, and the answers you have don't explain why it doesn't.
A type declaration like
type T_Norm is new float range -1.0 .. 1.0;
is roughly equivalent to
type T_Norm'Base is new Float;
subtype T_Norm is T_Norm'Base range -1.0 .. 1.0;
The type (called the "base type") isn't given a name, though it can often be referenced with the 'Base attribute. The name that is given is to a subtype, called the "first-named subtype".
This distinction is important and is often not given enough attention. As explained by egilhh, T_Norm'Image is defined in terms of T_Norm'Base. This is also true of the arithmetic operators. For example, "+" is defined as
function "+" (Left : in T_Norm'Base; Right : in T_Norm'Base) return T_Norm'Base;
2.0 is clearly in the range of T_Norm'Base, so evaluating D + 1.0 doesn't violate any constraints, nor does passing it to T_Norm'Image. However, when you try to assign the resulting value to D, which has subtype T_Norm, a check is performed that the value is in the range of the subtype, and an exception is raised because the check fails.
This distinction is used in other places to make the language work reasonably. For example, a constrained array type
type A is array (1 .. 10) of C;
is roughly equivalent to
type A'Base is array (Integer range <>) of C;
subtype A is A'Base (1 .. 10);
If you do
V : A;
... V (2 .. 4)
you might expect problems because the slice doesn't have the bounds of A. But it works because the slice doesn't have subtype A but rather the anonymous subtype A'Base (2 ..4).
The definition of 'Image says:
For every scalar subtype S:
S'Image denotes a function with the following specification:
function S'Image(Arg : S'Base)
return String
As you can see, it takes a parameter of the base (unconstrained) type
T_Norm'Image(D + 1.0) neither assigns nor reads an out-of-range value. It asks for the 'Image attribute (string representation) of (D + 1.0), which is the same as asking for (1.0 + 1.0).
I can see two ways the confusion might arise. First, the name "attribute" could be misinterpreted to suggest that 'Image involves something intrinsic to D. It doesn't. The 'Image attribute is just a function, so D is just part of the expression that defines the value of the parameter (in your example = 2.0).
Second, the 'Image attribute comes from Float. Thus, any Float can be its parameter.
You can create a function that accepts only parameters of T_Norm'Range and make that function an attribute of T_Norm. See Ada Reference Manual 4.10.
Because you don't store a value greater than range in D.

ASN.1: Can the SIZE constraint be used to constrain SEQUENCE (not SEQUENCE OF)

Is the following type definition valid ASN.1 syntax?
MyType ::= SEQUENCE SIZE(2) {
theID OBJECT IDENTIFIER,
someNumber INTEGER OPTIONAL,
someString PrintableString OPTIONAL
}
I want to formally constrain the sequence such that for each instantiation exactly one of both optional attributes must be present.
PS: As SEQUENCE and SEQUENCE OF are encoded exactly the same way, I have the slight hope that this syntax is valid.
This syntax is not valid. SEQUENCE is like a struct type with fields, where each field can be of different type. SEQUENCE OF is like an array, where all nested types are of same type. Thus, in SEQUENCE OF you can set constraint to array size. Same rules apply to SET and SET OF, just unordered.
I would solve your problem this way: create a CHOICE of all your optional fields (without OPTIONAL modifier) and add this CHOICE to your main type:
MyChoice ::= CHOICE {
someNumber INTEGER,
someString PrintableString
}
MyType ::= SEQUENCE {
theID OBJECT IDENTIFIER,
myChoice < MyChoice
}
In this case, theID field is mandatory and exactly one of MyChoice elements is required.

Anonymous struct, difference between struct{}{} and {}

I have string to struct map in golang defined in the following way:
var Foo = map[string]struct{}{
"foo": struct{}{},
}
Gogland by default marks this declaration as warning, saying "Redundant type declaration".
var Foo = map[string]struct{}{
"foo": {},
}
Above code solves the warning, but I couldn't find any information about the difference between struct{}{} and {} declaration. Is it kind of a "short notation"?
https://play.golang.org/p/0Akx98XtB4
This:
struct{}{}
is a composite literal which contains the type (struct{}) and the literal's value ({}).
This:
{}
is also a composite literal without the type, just the value.
Generally you have to specify / include the type in the composite literal to let the compiler know what kind of (what "type" of) composite literal you're creating, hence the syntax is:
CompositeLit = LiteralType LiteralValue .
But when you specify a map composite literal, the types of the key and value are known from the map type, and thus may be omitted if you intend to specify values of those types. This is mentioned in Spec: Composite literals:
Within a composite literal of array, slice, or map type T, elements or map keys that are themselves composite literals may elide the respective literal type if it is identical to the element or key type of T. Similarly, elements or keys that are addresses of composite literals may elide the &T when the element or key type is *T.
(Note: due to an oversight, this is only valid from Go 1.5.)

Does Go (deep) copy keys when inserting into a map?

I have a map with complex keys - for example, 2D arrays:
m := make(map[[2][3]int]int)
When I insert a new key into the map, does Go make a deep copy of the key?
a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
m[a] = 1
In other words, if I change the array a after using it as a map key, does the map still contain the old value of a?
Short answer, it is copied.
By specification, Arrays are value types.
Go's arrays are values. An array variable denotes the entire array; it is not a pointer to the first array element (as would be the case in C). This means that when you assign or pass around an array value you will make a copy of its contents. (To avoid the copy you could pass a pointer to the array, but then that's a pointer to an array, not an array.)
https://blog.golang.org/go-slices-usage-and-internals
See for yourself:
https://play.golang.org/p/fEUYWwN-pm
package main
import (
"fmt"
)
func main() {
m := make(map[[2][3]int]int)
a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Printf("Pointer to a: %p\n", &a)
m[a] = 1
for k, _ := range m {
fmt.Printf("Pointer to k: %p\n", &k)
}
}
The pointers do not match.
EDIT: The real reason is when inserting into a map, the key value is copied. Or, you can continue to just remember the rule above: arrays are value types and their reuse denotes a copy. Either works here. :)
Arrays are always passed by value, so, yes in this case Go will make a deep copy of the key.
From the language spec
The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
The keys are copied into the map. Excluding map and slice as valid keys means that the keys can't change. Note that go doesn't follow pointers if you define a map type with a pointer as a key (eg map[*int]int) it compares the pointers directly.

Extract nth element of a tuple

For a list, you can do pattern matching and iterate until the nth element, but for a tuple, how would you grab the nth element?
TL;DR; Stop trying to access directly the n-th element of a t-uple and use a record or an array as they allow random access.
You can grab the n-th element by unpacking the t-uple with value deconstruction, either by a let construct, a match construct or a function definition:
let ivuple = (5, 2, 1, 1)
let squared_sum_let =
let (a,b,c,d) = ivuple in
a*a + b*b + c*c + d*d
let squared_sum_match =
match ivuple with (a,b,c,d) -> a*a + b*b + c*c + d*d
let squared_sum_fun (a,b,c,d) =
a*a + b*b + c*c + d*d
The match-construct has here no virtue over the let-construct, it is just included for the sake of completeness.
Do not use t-uples, Don¹
There are only a few cases where using t-uples to represent a type is the right thing to do. Most of the times, we pick a t-uple because we are too lazy to define a type and we should interpret the problem of accessing the n-th field of a t-uple or iterating over the fields of a t-uple as a serious signal that it is time to switch to a proper type.
There are two natural replacements to t-uples: records and arrays.
When to use records
We can see a record as a t-uple whose entries are labelled; as such, they are definitely the most natural replacement to t-uples if we want to access them directly.
type ivuple = {
a: int;
b: int;
c: int;
d: int;
}
We then access directly the field a of a value x of type ivuple by writing x.a. Note that records are easily copied with modifications, as in let y = { x with d = 0 }. There is no natural way to iterate over the fields of a record, mostly because a record do not need to be homogeneous.
When to use arrays
A large² homogeneous collection of values is adequately represented by an array, which allows direct access, iterating and folding. A possible inconvenience is that the size of an array is not part of its type, but for arrays of fixed size, this is easily circumvented by introducing a private type — or even an abstract type. I described an example of this technique in my answer to the question “OCaml compiler check for vector lengths”.
Note on float boxing
When using floats in t-uples, in records containing only floats and in arrays, these are unboxed. We should therefore not notice any performance modification when changing from one type to the other in our numeric computations.
¹ See the TeXbook.
² Large starts near 4.
Since the length of OCaml tuples is part of the type and hence known (and fixed) at compile time, you get the n-th item by straightforward pattern matching on the tuple. For the same reason, the problem of extracting the n-th element of an "arbitrary-length tuple" cannot occur in practice - such a "tuple" cannot be expressed in OCaml's type system.
You might still not want to write out a pattern every time you need to project a tuple, and nothing prevents you from generating the functions get_1_1...get_i_j... that extract the i-th element from a j-tuple for any possible combination of i and j occuring in your code, e.g.
let get_1_1 (a) = a
let get_1_2 (a,_) = a
let get_2_2 (_,a) = a
let get_1_3 (a,_,_) = a
let get_2_3 (_,a,_) = a
...
Not necessarily pretty, but possible.
Note: Previously I had claimed that OCaml tuples can have at most length 255 and you can simply generate all possible tuple projections once and for all. As #Virgile pointed out in the comments, this is incorrect - tuples can be huge. This means that it is impractical to generate all possible tuple projection functions upfront, hence the restriction "occurring in your code" above.
It's not possible to write such a function in full generality in OCaml. One way to see this is to think about what type the function would have. There are two problems. First, each size of tuple is a different type. So you can't write a function that accesses elements of tuples of different sizes. The second problem is that different elements of a tuple can have different types. Lists don't have either of these problems, which is why you can have List.nth.
If you're willing to work with a fixed size tuple whose elements are all the same type, you can write a function as shown by #user2361830.
Update
If you really have collections of values of the same type that you want to access by index, you should probably be using an array.
here is a function wich return you the string of the ocaml function you need to do that ;) very helpful I use it frequently.
let tup len n =
if n>=0 && n<len then
let rec rep str nn = match nn<1 with
|true ->""
|_->str ^ (rep str (nn-1))in
let txt1 ="let t"^(string_of_int len)^"_"^(string_of_int n)^" tup = match tup with |" ^ (rep "_," n) ^ "a" and
txt2 =","^(rep "_," (len-n-2)) and
txt3 ="->a" in
if n = len-1 then
print_string (txt1^txt3)
else
print_string (txt1^txt2^"_"^txt3)
else raise (Failure "Error") ;;
For example:
tup 8 6;;
return:
let t8_6 tup = match tup with |_,_,_,_,_,_,a,_->a
and of course:
val t8_6 : 'a * 'b * 'c * 'd * 'e * 'f * 'g * 'h -> 'g = <fun>

Resources