Named arguments shortcut for Crystal - crystal-lang

In code below named arguments have to be duplicated, is there a way to shorten the expression?
struct Figure
getter id : String
getter hash : String
getter title : String
def initialize(#id, #hash, #title)
end
end
id = "Figure 1", hash = "123", title = "Some figure"
Figure.new id: id, hash: hash, title: title
Something like code below, yet keep it named not positional?
Figure.new id, hash, title
or maybe
Figure.new{ id, hash, title }

I don't know of a way to shorten this.
I think this would be a dangerous semantic when you tie the names of local variables to the names of method arguments because changing things on one place would have unforeseeable effects in another place.
Using positional arguments should be fine for most use cases. And in cases where you want to skip some arguments, you can just combine positional and named arguments.

Related

Terraform Splat Expression Giving "Invalid template interpolation value"

I am using data sources in Terraform to fetch a list of ids of my security groups as such:
data "aws_security_groups" "test" {
filter {
name = "group-name"
values = ["the-name"]
}
}
output "security_group_id" {
value = "The id is ${data.aws_security_groups.test.ids[*]}"
}
However, this is giving me the following error:
Error: Invalid template interpolation value
on main.tf line 11, in output "security_group_id":
11: value = "The id is ${data.aws_security_groups.test.ids[*]}"
|----------------
| data.aws_security_groups.test.ids is list of string with 1 element
Cannot include the given value in a string template: string required.
But if I use data.aws_security_groups.test.ids[0] instead it displays the ID.
Can someone help me to display the list of IDs?
First, I want to note that you don't necessarily need to combine this list with a string message at all if you don't want to, because Terraform will accept output values of any type:
output "security_group_ids" {
value = data.aws_security_groups.test.ids
}
If having them included as part of a bigger string is important for your underlying problem then you'll need to make a decision about how you want to present these multiple ids in your single string. There are various different ways you could do that, depending on what you intend to do with this information.
One relatively-straightforward answer would be to make the string include a JSON representation of the list using jsonencode, like this:
output "security_group_id_message" {
value = "The ids are ${jsonencode(data.aws_security_groups.test.ids)}"
}
If you want a more human-friendly presentation then you might prefer to use a multi-line string instead, in which case you can customize the output using string templates.
output "security_group_id_message" {
value = <<-EOT
The ids are:
%{ for id in data.aws_security_groups.test.ids ~}
- ${id}
%{ endfor ~}
EOT
}
Or, for an answer somewhere in between, you could use join to just concatenate the values together with a simple delimiter, like this:
output "security_group_id_message" {
value = "The ids are ${join(",", data.aws_security_groups.test.ids)}"
}
Note that I removed the [*] from your reference in all of these examples, since it isn't really doing anything here: data.aws_security_groups.test.ids is already an iterable collection, and so is compatible with all of the language features I used in the examples above.
IIRC the provider considers this ids attribute to be a set of strings rather than a list of strings, and so that [*] suffix could potentially be useful in other situations to force converting the set into a list if you need it to be typed that way, although if that is your intent then I'd suggest using one of the following instead so that it's clearer to a future reader what it does:
sort(data.aws_security_groups.test.ids) (if it being in lexical order is important to the behavior; Terraform uses lexical sorting by default anyway, but calling sort is a good prompt to a reader unfamiliar with Terraform to look up that function to see what the actual sort order is.)
tolist(data.aws_security_groups.test.ids) (functionally equivalent to sort above when it's a set of strings, but avoids the implication that the specific ordering is important, if all that matters is that it's a list regardless of the ordering)

Can tuple literals in C# 7.0 enable aspect oriented programming

I'm referring to tuple literals as described here: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/#comment-321926
Love the tuple literal idea.
However I foresee a lot of looking up the order of the items in return tuples and would like to know how we can get around this.
Wouldn’t it make more sense for example to have the name of the item in the tuple be the identity defining aspect, instead of the order? Or is there a way to do this I'm not seeing?
For example: suppose NextEmployee() is some library method that I don’t have the source code of, and isn’t particularly well documented, and suppose it returns (firstname: “jamie”, lastname: “hince”, id: 102348) to me, and I say:
(string lastname, var _, int __) = NextEmployee(); // I only need the last name
The compiler would either happily assign firstname to lastname, or warn or error about it. Why not just map lastname to lastname?
I’d see that allowing for more loosely coupled architecture, if we didn’t have to remember the index of lastname in the tuple, and could just ask for an aspect “lastname” like that.
Tuples are intended to be just a bag of variables. As variables, you can assign any value assignable to the variable type regardless of the variable name.
The names are only an indication as variable names are. The only difference in return values is that the compiler persists the name of the tuple elements using TupleElementNames attribute.
In fact, even in the presence of the names, the compiler warns you if you don't use the same names as, usually, it's a mistake and still valid syntax:
(string firstname, string lastname, int id) NextEmployee()
=> (apples: "jamie", potatos: "hince", oranges: 102348);
/*
Warning CS8123 The tuple element name 'apples' is ignored because a different name is specified by the target type '(string firstname, string lastname, int id)'.
Warning CS8123 The tuple element name 'potatos' is ignored because a different name is specified by the target type '(string firstname, string lastname, int id)'.
Warning CS8123 The tuple element name 'oranges' is ignored because a different name is specified by the target type '(string firstname, string lastname, int id)'.
*/
The syntax your using here:
(string lastname, var _, int __) = NextEmployee();
is not tuple declaration syntax, but tuple deconstruction syntax that creates a LastName variable, a _ variable and a __ variable.
These are all equivalents that produce the same result:
(var lastname, var _, var __) = NextEmployee(); // or any combination ofvarand type names
var (lastname, _, __) = NextEmployee();
To declare a tuple to receive the return of the method, you would need to declare a tuple variable:
(string firstname, string lastname, int id) t = NextEmployee();
var t = NextEmployee();
But it seems your intent is to ignore the LastName and id values:
(_, string lastname, _) = NextEmployee(); // declares a lastname variable and ignores firstname and id
But if you really write (string lastname, _, _) = NextEmployee();, then you are assigning a local string variable named lastname with the value of the returned string "variable" firstname.
Just remember, tuples are not entities. They are sets of values. If the library you are using uses tuples as entities, be aware that chances are something else might be wrong with that library.
Why not? Well because the underlying runtime doesn't even know about the names.
The compiler would have to do it during compilation. And where do we stop? What about typos, capitalization, etc?
In my opinion, the way it currently is right now is okay.
If you feel different about this subject, ask your question over at the official language design repository on github by raising an issue:
https://www.github.com/dotnet/csharplang
Paulo explained the technical details pretty well already so I'm not going to repeat that.

Syntax for list delimiters in template

I'm writing an application that allows the user to configure the output using templates. For example:
Variables:
name = "BoppreH"
language = "Python"
Template:
My name is {name} and I like {language}.
Output:
My name is BoppreH and I like Python.
This works fine for simple data, like strings and numbers, but I can't find a good syntax for lists, more specifically for their delimiters.
fruits = ["banana", "apple", "watermelon"]
I like {???}.
I like banana, apple, watermelon.
In this case the desired delimiter was a comma, but how can the user specify that? Is there some template format with this feature?
I'm more concerned about making the syntax simple to understand, regardless of language or library.
Implement filters, and require their use for non-scalar types.
I like {fruits|join:", "}.
Typically, a list contains an unknown number of members, and sometimes variables/placeholders of its own. An example might be listing the name of a person along with their phone numbers. The desired output might look something like this:
John Doe
555-1212
555-1234
In a templating system that supported this, you'd need two types of variables: One that designated a placeholder for a value (like the curly braces you're using now), and another to denote the start and end of the list. So, something like this:
{name}
{{phone_numbers}}{phone}{{/phone_numbers}}
Your array of values might look like this:
values = [names: "John Doe", phone_numbers: [ phone: "555-1212", phone: "555-1234"]]
Each value in the "phone_numbers" array would create a new instance of everything that existed between {{phone_numbers}} and {{/phone_numbers}}, placing the values contained within those two "tags".

How can I get property name and property value from json-cpp parser?

I'm using jsoncpp parser (http://jsoncpp.sourceforge.net) to parse JSON data.
So, if we have the following JSON:
{ "name": "Joseph", "age": 20 }
How can I get the property name name and value Joseph, ... after age and 20?
OK, we can do universally this:
string e = root.get(propertyName, defaultValue).asString();
But really what we want is something like this:
string e = root.get(name, "Mark").asString();
Now, variable e is Joseph, it works. But I have to take/write "name". I do not want to QUERY (without questioning the function I want to get "name" (name of property) and "Joseph" (value of property)).
After it would be best to store in a field (C/C++ for example):
property[name][0] = "Joseph"
property[age][0] = 20
How can I do that? Or any other ideas?
You can get all the member names of a Json::Value object using its getMemberNames() function. That returns an object that you can iterate over using .begin() and .end(), like any other standard library container. (In fact, the return type is an alias for std::vector<std::string>.)
After you have the member names, you should be able to iterate through them and use .get(std::string &, const ValueType &) as you already are doing to get the values for each of the object's keys.
Note that JSON objects are inherently unordered, so you can't necessarily rely on that name list having any ordering whatsoever. If you want an ordered object, you should be using JSON arrays, not JSON objects.

How to read semicolon separated certain values from a QString?

I am developing an application using Qt/KDE. While writing code for this, I need to read a QString that contains values like ( ; delimited)
<http://example.com/example.ext.torrent>; rel=describedby; type="application/x-bittorrent"; name="differentname.ext"
I need to read every attribute like rel, type and name into a different QString. The apporach I have taken so far is something like this
if (line.contains("describedby")) {
m_reltype = "describedby" ;
}
if (line.contains("duplicate")) {
m_reltype = "duplicate";
}
That is if I need to be bothered only by the presence of an attribute (and not its value) I am manually looking for the text and setting if the attribute is present. This approach however fails for attributes like "type" and name whose actual values need to be stored in a QString. Although I know this can be done by splitting the entire string at the delimiter ; and then searching for the attribute or its value, I wanted to know is there a cleaner and a more efficient way of doing it.
As I understand, the data is not always an URL.
So,
1: Split the string
2: For each substring, separate the identifier from the value:
id = str.mid(0,str.indexOf("="));
value = str.mid(str.indexOf("=")+1);
You can also use a RegExp:
regexp = "^([a-z]+)\s*=\s*(.*)$";
id = \1 of the regexp;
value = \2 of the regexp;
I need to read every attribute like rel, type and name into a different QString.
Is there a gurantee that this string will always be a URL?
I wanted to know is there a cleaner and a more efficient way of doing it.
Don't reinvent the wheel! You can use QURL::queryItems which would parse these query variables and return a map of name-value pairs.
However, make sure that your string is a well-formed URL (so that QURL does not reject it).