Kotlin: Use specific values as a type - kotlin

I want to model the result of two six sided dice in Kotlin.
In TypeScript you can do something like this:
type SixSidedDie = 1 | 2 | 3 | 4 | 5 | 6
I would like to do something similar in Kotlin with
typealias SixSidedDie = 1 | 2 | 3 | 4 | 5 | 6
Which of course doesn't work because the compiler expects a type.
Is there any way in Kotlin to use constant values as a type?

Is there any way in Kotlin to use constant values as a type?
Not at the moment, and I haven't seen it discussed so far. This is because, without union types, I don't think those are really useful (you could use objects for that purpose).
There is an issue tracking the possible addition of denotable union types to the language: https://youtrack.jetbrains.com/issue/KT-13108/Denotable-union-and-intersection-types
Now about your precise use case, there is also nothing currently available in Kotlin to represent subsets of numbers as a type. The closest you can get, as mentioned in the comment, is an enum:
enum class Dice6Result {
ONE, TWO, THREE, FOUR, FIVE, SIX
}
Or with an associated Int value if you need it:
enum class Dice6Result(val value: Int) {
ONE(1), TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6)
}
Note, that union types still would not solve the Int subset problem unless constant values could be used as types (as you were asking for).
Another option for you could be to use a value class to wrap the integer value, and check in an init block at construction time that the value is within the bounds. However, this becomes a runtime check, which might be less interesting than an enum.

Related

How to express union types in Kotlin?

Union types, also known as sum types are a powerful language feature that I find myself using often in TypeScript
something along the lines of:
let a: string | number = “hello”
a = 3
How would I achieve this type of behavior in kotlin?
I saw some people talking about using inheritance and sealed classes to accomplish this but it looks like if you want to use that approach with primitives (such as String and Int) then one would have to write wrappers around those types to access the underlying value.
Im wondering if there is a more pragmatic solution.
There is an issue in Kotlin issue tracker: Denotable union and intersection types (it also contains links to a few previous discussions). The last update from the team is
Roman Elizarov commented 19 Nov 2021 18:14
Short update on this issue. This is an interesting and important feature, but it is really hard to integrate into the language in a backward-compatible and pragmatic way. We'll start working on it fully when we release the new K2 compiler and the best compiler engineers from our team will be able to start looking into it.
As far as I know, there isn't really a "pretty" way to do it in kotlin
One way to achieve a variable that can hold strings and ints could look like that:
var x: Any = 5
x = "hello"
but as you can notice, X can hold any type not only strings and ints, but you could use the "Either" class, from Arrow library (If I'm not mistaken) which allows such behaviour:
var x = Either<Int, String>(5)
Either way, I'm not really sure why would you need such a variable

Did Objective C start using + instead of | for combining bits?

Anytime you combine two flags or more, you use |. Except Swift, which changed it to use array syntax. But now I am staring at some documentation on local notifications that does this:
requestAuthorizationWithOptions: (UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
Where those are enums. I can't find where the + operator suddenly started working in this manner. I don't see any indicators that | couldn't just be used instead. I realize that maybe the enums themselves could just happen to work by the nature of their bits and how they add, but I doubt my last statement.
So, to codify the discussion in comments above: no, + is not a replacement for |. a + b == a | b if and only if a and b have bitpatterns which share no overlapping bits; in the cases of option enums, this is often true (because it is useful to represent options in this way), but not guaranteed. This is the case that you see above, though good code will be a bit more explicit (and readable) by using bitwise or.

Converting Ordered Collection to Literal Array

I have an ordered collection that I would like to convert into a literal array. Below is the ordered collection and the desired result, respectively:
an OrderedCollection(1 2 3)
#(1 2 3)
What would be the most efficient way to achieve this?
The message asArray will create and Array from the OrderedCollection:
anOrderedCollection asArray
and this is probably what you want.
However, given that you say that you want a literal array it might happen that you are looking for the string '#(1 2 3)' instead. In that case I would use:
^String streamContents: [:stream | aCollection asArray storeOn: stream]
where aCollection is your OrderedCollection.
In case you are not yet familiar with streamContents: this could be a good opportunity to learn it. What it does in this case is equivalent to:
stream := '' writeStream.
aCollection asArray storeOn: stream.
^stream contents
in the sense that it captures the pattern:
stream := '' writeStream.
<some code here>
^stream contents
which is fairly common in Smalltalk.
UPDATE
Maybe it would help if we clarify a little bit what do we mean literal arrays in Smalltalk. Consider the following two methods
method1
^Array with: 1 with: 2 with: 3
method2
^#(1 2 3)
Both methods answer with the same array, the one with entries 1, 2 and 3. However, the two implementations are different. In method1 the array is created dynamically (i.e., at runtime). In method2 the array is created statically (i.e., at compile time). In fact when you accept (and therefore compile) method2 the array is created and saved into the method. In method1instead, there is no array and the result is created every time the method is invoked.
Therefore, you would only need to create the string '#(1 2 3)' (i.e., the literal representation of the array) if you were generating Smalltalk code dynamically.
You can not convert an existing object into a literal array. To get a literal array you'd have to write it using the literal array syntax in your source code.
However, I believe you just misunderstood what literal array means, and you are infact just looking for an array.
A literal array is just an array that (in Pharo and Squeak [1]) is created at compile time, that is, when you accept the method.
To turn an ordered collection into an array you use asArray.
Just inspect the results of
#(1 2 3).
(OrderedCollection with: 1 with: 2 with: 3) asArray.
You'll see that both are equal.
[1]: see here for an explanation: https://stackoverflow.com/a/29964346/1846474
In Pharo 5.0 (a beta release) you can do:
| oc ary |
oc := OrderedCollection new: 5.
oc addAll: #( 1 2 3 4 5).
Transcript show: oc; cr.
ary := oc asArray.
Transcript show: ary; cr.
The output on the transcript is:
an OrderedCollection(1 2 3 4 5)
#(1 2 3 4 5)
the literalArray encoding is a kind of "poor man's" persistency encoding to get a representation, which can reconstruct the object from a compilable literal array. I.e. an Array of literals, which by using decodeAsLiteralArray reconstructs the object.
It is not a general mechanism, but was mainly invented to store UI specifications in a method (see UIBuilder).
Only a small subset of classes support this kind of encoding/decoding, and I am not sure if OrderedCollection does it in any dialect.
In the one I use (ST/X), it does not, and I get a doesNotUnderstand.
However, it would be relatively easy to add the required encoder/decoder and make it possible.
But, as I said, its intended use is for UIspecs, not as a general persistency (compiled-object persistency) mechanism. So I rather not recommend using it for such.

Are mixed type indexes acceptable in Neo4j?

I have a data set which includes a number of nodes, all of which labeled claim, which can have various properties (names P1, P2, etc., through P2000). Currently, each of the claim nodes can have only one of these properties, and each property has value, which can be of different types (i.e. P1 may be string, P2 may be float, P3 integer, etc.). I also need to be able to look up the nodes by any property (i.e. "find all nodes with P3 which equals to 42").
I have modeled it as nodes having property value and label according to the P property. Then I define schema index on label claim and property value. The lookup then would look something like:
MATCH (n:P569:claim) WHERE n.value = 42 RETURN n
My first question is - is this OK to have such index? Are mixed type indexes allowed?
The second question is that the lookup above works (though I'm not sure whether it uses index or not), but this doesn't - note the label order is switched:
neo4j-sh (?)$ MATCH (n:claim:P569) WHERE n.value>0 RETURN n;
IncomparableValuesException: Don't know how to compare that. Left: "113" (String); Right: 0 (Long)
P569 properties are all numeric, but there are string properties from other P-values one of which is "113". Somehow, even though I said the label should be both claim and P569, the "113" value is still included in the comparison, even though it has no P569 label:
neo4j-sh (?)$ MATCH (n:claim) WHERE n.value ="113" RETURN LABELS(n);
+-------------------+
| LABELS(n) |
+-------------------+
| ["claim","P1036"] |
| ["claim","P902"] |
+-------------------+
What is wrong here - why it works with one label order but not another? Can this data model be improved?
Let me at least try to side-step your question, there's another way you could model this that would resolve at least some of your problems.
You're encoding the property name as a label. Perhaps you want to do that to speed up looking up a subset of nodes where that property applies; still it seems like you're causing a lot of difficulty by shoe-horning incomparable data values all into the same property named "value".
What if, in addition to using these labels, each property was named the same as the value? I.e.:
CREATE (n:P569:claim { P569: 42});
You still get your label lookups, but by segregating the property names, you can guarantee that the query planner will never accidentally compare incomparable values in the way it builds an execution plan. Your query for this node would then be:
MATCH (n:P569:claim) WHERE n.P569 > 5 AND n.P569 < 40 RETURN n;
Note that if you know the right label to use, then you're guaranteed to know the right property name to use. By using properties of different names, if you're logging your data in such a way that P569's are always integers, you can't end up with that incomparable situation you have. (I think that's happening because of the particular way cypher is executing that query)
A possible downside here is that if you have to index all of those properties, it could be a lot of indexes, but still might be something to consider.
I think it makes sense to take a step back and think what you actually want to achieve, and why you have those 2000 properties in the first place and how you could model them differently in a graph?
Also make sure to just leave off properties you don't need and use coalesce() to provide the default.

How to tell if an identifier is being assigned or referenced? (FLEX/BISON)

So, I'm writing a language using flex/bison and I'm having difficulty with implementing identifiers, specifically when it comes to knowing when you're looking at an assignment or a reference,
for example:
1) A = 1+2
2) B + C (where B and C have already been assigned values)
Example one I can work out by returning an ID token from flex to bison, and just following a grammar that recognizes that 1+2 is an integer expression, putting A into the symbol table, and setting its value.
examples two and three are more difficult for me because: after going through my lexer, what's being returned in ex.2 to bison is "ID PLUS ID" -> I have a grammar that recognizes arithmetic expressions for numerical values, like INT PLUS INT (which would produce an INT), or DOUBLE MINUS INT (which would produce a DOUBLE). if I have "ID PLUS ID", how do I know what type the return value is?
Here's the best idea that I've come up with so far: When tokenizing, every time an ID comes up, I search for its value and type in the symbol table and switch out the ID token with its respective information; for example: while tokenizing, I come across B, which has a regex that matches it as being an ID. I look in my symbol table and see that it has a value of 51.2 and is a DOUBLE. So instead of returning ID, with a value of B to bison, I'm returning DOUBLE with a value of 51.2
I have two different solutions that contradict each other. Here's why: if I want to assign a value to an ID, I would say to my compiler A = 5. In this situation, if I'm using my previously described solution, What I'm going to get after everything is tokenized might be, INT ASGN INT, or STRING ASGN INT, etc... So, in this case, I would use the former solution, as opposed to the latter.
My question would be: what kind of logical device do I use to help my compiler know which solution to use?
NOTE: I didn't think it necessary to post source code to describe my conundrum, but I will if anyone could use it effectively as a reference to help me understand their input on this topic.
Thank you.
The usual way is to have a yacc/bison rule like:
expr: ID { $$ = lookupId($1); }
where the the lookupId function looks up a symbol in the symbol table and returns its type and value (or type and storage location if you're writing a compiler rather than a strict interpreter). Then, your other expr rules don't need to care whether their operands come from constants or symbols or other expressions:
expr: expr '+' expr { $$ = DoAddition($1, $3); }
The function DoAddition takes the types and values (or locations) for its two operands and either adds them, producing a result, or produces code to do the addition at run time.
If possible redesign your language so that the situation is unambiguous. This is why even Javascript has var.
Otherwise you're going to need to disambiguate via semantic rules, for example that the first use of an identifier is its declaration. I don't see what the problem is with your case (2): just generate the appropriate code. If B and C haven't been used yet, a value-reading use like this should be illegal, but that involves you in control flow analysis if taken to the Nth degree of accuracy, so you might prefer to assume initial values of zero.
In any case you can see that it's fundamentally a language design problem rather than a coding problem.