Iterate union type in a macro - crystal-lang

Is there a way to iterate over types in a union type in a macro? Here is my try:
alias MyType = Int32 | String
{% for type in MyType.union_types %} #=> undefined method 'union_types' for TypeNode of type MyType (must be a union type)
...
{% end %}
I tried to use TypeNode#union_types method, but seems like MyType is not considered as a union type at all:
{% puts MyType.union? %} #=> false

It looks like it's currently impossible to use complex alias types in macros. This is a bug, please bump crystal-lang/crystal#4301 with your example.

maybe typeof method will help you
alias MyType = Int32 | String
puts typeof(MyType) # => (Int32 | String):Class
try here

Related

Explain syntax for returning array by reference from a function

The syntax of function in C++ is:
return_type function_name(parameter1, parameter2, ...)
{
// function body
}
I have some doubts regarding "returning reference of an array from a function":
Return type is specified first then function name but to return reference of an array it is written as:
// for array of size 10
int (&f())[10] {
return global;
}
why?
Can it be written as below:
// return type followed by function name
int&[10] f(){
return global;
}
or something similar(without typedef)?
I couldn't understand typedef usage when using it like:
typedef int array_t[10];
array_t& f() {
return global;
}
how will the above code be simplified? and will the simplified code look like the code in point 1?
why?
Because Dennis Ritchie designed it to be so in C, and because C++ was designed to be compatible with C.
There weren't references in C of course, but references follow the same syntax rules as pointers do, which were inherited from C.
The main confusion however doesn't seem to be about where the reference puncutator goes, but rather about the array syntax. The array size simply always goes to the right side of the name. This same pattern is also true for variables:
int arr[size];
| | |
| | size
| name
element type
int (&arr_ref)[size];
| | |
| | size
| name
element type
int (&f())[10]
| | |
| | size
| name
element type
Function declaration is different only in the regard that it has the parameter list. Which is always immediately after the name. And because it is immediately after the name, it is consequently before the array size.
Can it be written as below:
No. That is ill-formed in C++.
I couldn't understand typedef usage when using it like:
typedef is simply an alias; a different name for the type.
how will the this code be simplified?
The code in 3. is optimally simple. Personally, I prefer the using syntax for type aliases instead of typedef:
using array_t = int[10];
Another option is to use trailing return type, although it whether this is more or less simple is subjective:
auto f() -> int(&)[10] {
and will it look like the code in point 1?
The decaration looks different, but it declares the same function.

Losing type precision from module signature

Let's say I had a simple module MyFoo that looks something like this
module MyFoo = struct
type t =
| A of string
| B of int
let to_string thing =
match thing with
| A str -> str
| B n -> string_of_int n
end
With this definition, it works great and as expected — I can do something like
let _ = MyFoo.A "";;
- : MyFoo.t = MyFoo.A ""
without any problems.
Now maybe I want to create a functor that consumes modules with this structure, so I define a module signature that describes generally what this looks like and call it BaseFoo
module type BaseFoo = sig
type t
val to_string : t -> string
end
If I redefine MyFoo the same way but giving it this signature like
module MyFoo : BaseFoo = struct
type t =
| A of string
| B of int
let to_string thing =
match thing with
| A str -> str
| B n -> string_of_int n
end
I lose the precision of its type t (is there a better way to describe what happens here?) — for example:
let _ = MyFoo.A "";;
Error: Unbound constructor MyFoo.A
What exactly is going on here and why does it happen? Is there a canonical way for dealing with this kind of problem (besides just leaving off the signature)?
I've tried manually including the signature and the specific type type definition too but get a different kind of error (this probably isn't the right approach).
module MyFoo : sig
include BaseFoo
type t = | A of string | B of int
end = struct
type t =
| A of string
| B of int
let to_string thing =
match thing with
| A str -> str
| B n -> string_of_int n
end
let _ = MyFoo.A "test";;
Error: Multiple definition of the type name t.
Names must be unique in a given structure or signature.
You don't need the signature
What is going on is pretty much what you describe: giving MyFoo the BaseFoo signature in its definition restricts it to the signature.
Why? Because this is what specifying a signature at this place is for. The canonical solution is to leave of the signature (usually, letting the signature definition next to the module definition will be clear enough for the reader).
Note that when you call MyFoo on your functor, the signature will be checked. My usual choice is to rely on that.
A few workarounds
Given what you've tried, I guess this could be interesting to you:
module type BaseFoo = sig ... end
module MyFoo = struct ... end
module MyFooHidden : BaseFoo = MyFoo (* Same as defining MyFoo : BaseFoo *)
module MyFooWithType :
BaseFoo with type t = MyFoo.t
= MyFoo (* What you want *)
The with type t = t' clause allows you to annotate a module signature to add type information to it. It is quite useful, especially when dealing with functors. See here for more information.
MyFooHidden may seem useless, but you can see it as a check that MyFoo has the right signature. You can still use MyFoo however you want after all. MyFooWithType is actually (a bit) less useful because if you change your signature to add a type you'd want exported, you'd need to add the export here too.
Using include
As for your include try. Well, nice try! You were almost there:
module MyFoo : sig
type t = A of string | B of int
include BaseFoo with type t := t
end
The with type t := t' is a bit different in that it doesn't perform an equality but a replacement. The type t definition is removed from the BaseFoo signature altogether and all instances are replaced with your own t, that way you don't get any double definition problem. See here for more details.
As you point out, this is probably not the approach you want, as you no longer easily know that MyFoo is indeed a BaseFoo.

Ambiguity with pattern matching records

I learned from this question that it's possible to use pattern matching with records. However, I've noticed that I'm having trouble trying to match different types of records.
My goal in this example is to be able to distinguish between different records. I'm given a record that I'm not entirely sure which type it is, and I'm trying to figure it out using pattern matching.
Here's a simplified example:
module IceCream = struct
type t = {
temperature: float;
toppings: string list;
}
end
module Candy = struct
type t = {
flavour: string;
colour: string;
volume: int;
}
end
(* Could be Candy or IceCream *)
let example =
{ Candy.
flavour = "mint";
colour = "green";
volume = 10 }
let printFavoriteTreat treat = match treat with
| { Candy.
flavour = "mint";
colour;
volume } -> "It's Candy"
| { IceCream.
temperature;
toppings } -> "It's IceCream"
let () = printFavoriteTreat example
When I try to build this file, I get:
Error: The field IceCream.temperature belongs to the record type IceCream.t
but a field was expected belonging to the record type Candy.t
Is doing something like this possible?
I'm given a record that I'm not entirely sure which type it is, and I'm trying to figure it out using pattern matching.
That is not possible. Types exist only at compile time, so checking what type it is at runtime is not possible.
In other words, in a valid program you can put a type annotation on every expression (in most cases you do not have to do that, though, thanks to type inference). If you cannot do that then you should design your program differently, such as using a sum type as others have suggested - in that case both values will have the same type (at compile time) but a different constructor (at run time).
The answer provided by Pierre is great, but the example not so much. (I've always hated examples named a, b...)
So, as Pierre suggests, you could define your types like this:
type ice_cream = {
temperature: float;
toppings: string
}
type candy = {
flavor: string;
color: string;
volume: int
}
Then, you can define a type treat as a variant of these two types:
type treat =
| Candy of candy
| IceCream of ice_cream
Then, using pattern-matching:
let print_favorite_treat = function
| Candy _ -> print_endline "You love candy!"
| IceCream _ -> print_endline "You love ice cream!"
You are trying to match against to different types without using variant types.
The module syntax you are using cannot help, as module just structure the code. You could have defined the following types :
type a = {
temperature: float;
toppings: string list;
}
type b = {
flavour: string;
colour: string;
volume: int;
}
But the results would be the same.
The way to disambiguate is to use variant types (or union type which is not described in the example below) :
let printFavoriteTreat treat = match treat with
| `A{ Candy.
flavour = "mint";
colour;
volume } -> "It's Candy"
| `B { IceCream.
temperature;
toppings } -> "It's IceCream"
;;
And
let () = printFavoriteTreat (`A example)

Ternary expression which "does nothing" (noop) if the condition is false?

Out of curiosity I started wondering if it's possible to have a ternary expression that, if it evaluates to false, does nothing in the false branch.
Ie is there a way to write something like this:
variable = (someBool) ? i : <do nothing>;
As opposed to:
if (someBool) {
variable = i;
}
I tried ((void)0) or while(false){}; as no-op but the compiler expects an expression.
UPDATE:
I realized the question lost some meaning because I tried to make the code easier. The initial idea I had was to initialize a static var with a ternary - using the static var itself as the condition:
static int var = (var != 0) ? var = 1 : (var already initialized, do nothing);
This is assuming that uninitialized variables are initialized to 0 which is not always true (or never in release builds, not quite sure). So maybe it's a hypothetical question.
how about short-circuit?
int variable = 0;
bool cond = true; // or false
(cond && (variable = 42));
printf("%d\n", variable);
How about this:
variable = (someBool) ? i : variable ;
Though I would personally prefer the original if statement
Compilers not only expect expression, but the expression the returns type on the left side (the type of variable whatever is it). So, no you can not do that. It's not conditional execution, but variable member assignment.
These are completely different things.
In second example :
if (someBool) {
variable = i;
}
you do not assign anything, but simply execute based on condition. So in your case, where you don't want to do anything (not assign anything), the way to go is conditional execution so use simply the second case.
The format of the conditional expression is
<expression> ? <expression> : <expression>
In other words, it must have some expression.
Addressing your edit: in C99 variables of static scope are initialised to 0. However, I have never really trusted that because I've been programming in C since the K&R days.
Anyway, just initialise the variable. As the variable is static, it's only going to happen once during the whole execution time of the program.
You could do:
variable = !someBool ?: i;
Since the ?: will no-op when the if expression is true but assign i if it's false.
Note: This has only been tested in Obj-C
How about
(someBool) ? (variable = i) : NULL;
For C# says:
Syntax:
condition ? first_expression : second_expression;
And it says about first_expression and second_expression:
Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
If you were to evaluate a nullable object type instead of bool, you could always write:
variable = myVar ?? i;
Hacky/cludgey/impractical - probably all 3, but for the sake of this question it's a way of omitting an 'else'.
Try: null lambda.
auto null_lambda = [](){return;};
int a = 1;
int b = 2;
vector<int> c;
a > c ? b = c.push_back(b) : null_lambda();

Struct initialization of the C/C++ programming language?

I could do struct initialization with code:
struct struct_type_id struct_name_id = { value1, value2, value3 };
but could not with:
struct struct_type_id struct_name_id;
struct_name_id = { value1, value2, value3 };
why I could do it with the former,but could not with the latter with gcc,g++,vc2008,vc6?In other words,why the c/c++ programming language do not support this syntax?
thanks.
The first statement creates a variable initialized to the given values, i.e., these values are built in memory and stored directly in the program executable in that variable address (for globals) or ready for memory copy (for stack variables).
The second statement of the second block is very different. Although it looks similar, it is an assign expression. It means that the RHS of the equals operator is an expression that is evaluated (independently of what is in the LHS of =), and then passed to the = operator. Without proper context, {...} doesn't have any meaning.
In C99, you can do this:
struct_name_id = (struct struct_type_id){ value1, value2, value3 };
Now the RHS of the equals operator is a valid expression, since there is proper context for the compiler to know what is in {...}.
In C++11, the syntax is:
struct_name_id = struct_type_id{ value1, value2, value3 };
I don't know why C didn't originally support some kind of syntax to 'reinitialize' a struct using something like the initializer list - there are definitely times when I would have found it handy. As Juliano mentioned, C99 (and C++0x) has fixed it to a certain degree, but I often have to stick with C90. When I want to do something like that, I'll sometimes do the following:
struct foo const init_foo = { 1, 2, 3};
struct foo myFoo;
// ....
myFoo = init_foo; // reinitialize myFoo
You just need to cast the values as such:
struct_name_id = (struct struct_type_id){ value1, value2, value3 };
I faced a similar problem, and the solution to that was that I was trying to initialized the struct outside the function(not using the initializer syntax, but with the obj.member = VALUE; notation). It is a related problem, so posting here, hoping someone with the same question lands up here.
Will this work for you ?
typedef struct name_id {int value1; int value2; int value3;} NAME_ID;
name_id mynameid = {0,1,2};