F# enum to string conversion - enums

I have a following F# enum
type DataType = AUCTION|TRANSACTION
I would like to use DataType as a parameter to a function, so that the values of the parameter is restricted to string AUCTION and TRANSACTION,
is that possible to convert the items in this enum to string, or is there a better way to contraint the value of a parameter to a set of string?

First of all, as several people have mentioned in the comments, the type you have defined is not an Enumeration, it's a Discriminated Union.
Enumerations are effectively just a label given to an integer and, in F#, are declared using this syntax:
type DataType =
|Auction = 1
|Transaction = 2
Using this syntax, you've got a relationship between the value and the associated integer, you can use the integer to get the value of an Enumeration, e.g.
let transaction = enum<DataType>(2) // Transaction
Note that there is nothing stopping you from saying enum<DataType>(3537), even though we haven't defined that case.
For more details on Enumerations, see: https://msdn.microsoft.com/en-us/library/dd233216.aspx
Discriminated Unions are much more flexible than Enumerations. Let's take a look at yours:
type DataType =
|Auction
|Transaction
This version is now actually a Standard .NET class with two case identifiers: Auction and Transaction. You can think of Auction and Transaction as two type constructors for DataType.
Discriminated Unions are not restricted to just simple cases, you could store additional data, e.g.
type DataType =
/// An auction with a list of bids
|Auction of Bid list
/// A transaction with some price in GBP
|Transaction of decimal<GBP>
With Disciminated Unions, there is no implicit relationships with integers, if we want to construct a particular case, we have to use the appropriate case identifier.
e.g. let auction = Auction (bidlist)
For more details on Discriminated Unions, see: https://msdn.microsoft.com/en-us/library/dd233226.aspx
In both cases, converting to a specific string for each case can be achieved using pattern matching.
For the Discriminated Union:
let datatypeToString datatype =
match datatype with
|Auction -> "AUCTION"
|Transaction -> "TRANSACTION"
And for the Enumeration:
let datatypeToString datatype =
match datatype with
|DataType.Auction -> "AUCTION"
|DataType.Transaction -> "TRANSACTION"
Notice that when you use Enumerations, F# will give you a compiler warning telling you that pattern matches cases aren't complete. This is because Enumerations are just ints and there are many ints besides just 1 and 2, this means that the match cases aren't exhaustive.
I therefore recommend you stick to Discriminated Unions and keep your exhaustive pattern matching.
P.S. If you want to go in the other direction, from string to DataType, I recommend using a tryCreateDataType function which would look something like this:
let tryCreateDataType str =
match str with
|"AUCTION" -> Some Auction
|"TRANSACTION" -> Some Transaction
|_ -> None
This returns an Option, so it will allow you to safely match against the function being successful or it failing due to an invalid string.

Related

Why does the golang place the type specifier "after" the variable name?

Just out of curiosity, why does the golang place the type specifier after the variable name like below. Have to? Or happen to?
type person struct {
name string
age int
}
Why not just like this? It's more natural IMHO, and it saves the type keyword.
struct person {
string name
int age
}
I think the Go programming language follows these principles:
declarations start with a keyword, so that the parser can be implemented with a single token look-ahead (like in Pascal)
the rest of the declaration follows the English grammar, with every redundant word left out (also like in Pascal, but with fewer keywords)
Examples:
The type Frequency is a map indexed by string, mapping to int
type Frequency map[string]int
The type Point is a struct with two fields, x and y of type int
type Point struct { x, y int }
The above sentences focus more on the names than on the types, which makes sense since the names convey more meaning.
If I had to explain to novice programmers how to write declarations in Go, I would let them first describe it in plain English and then remove every word that might even seem redundant.
Up to now, I didn't find any contradictions to these rules.

Checking for inequality against string variable fails

I have the code like this:
var query = repository.Where(item => item.UserId == userId && item.LoanNumber != loanNumber)
which is transformed to SQL (repository is IQueryable).
loanNumber is a string parameter in the method. The problem is that checking against inequality fails (ignored). If instead of variable I use constant with its value, it works properly.
What the... ?
A number should be a NUMBER DATA TYPE, and not a string. It violates normalization rules. So please tell what are the data type of the values being compared on both sides of the expression in predicate.
If you compare similar data types, you would get correct results as you don't and should not rely on implicit conversion.
So make sure you have the correct data type.

Convert Enum to Binary (via Integer or something similar)

I have an Ada enum with 2 values type Polarity is (Normal, Reversed), and I would like to convert them to 0, 1 (or True, False--as Boolean seems to implicitly play nice as binary) respectively, so I can store their values as specific bits in a byte. How can I accomplish this?
An easy way is a lookup table:
Bool_Polarity : constant Array(Polarity) of Boolean
:= (Normal=>False, Reversed => True);
then use it as
B Boolean := Bool_Polarity(P);
Of course there is nothing wrong with using the 'Pos attribute, but the LUT makes the mapping readable and very obvious.
As it is constant, you'd like to hope it optimises away during the constant folding stage, and it seems to: I have used similar tricks compiling for AVR with very acceptable executable sizes (down to 0.6k to independently drive 2 stepper motors)
3.5.5 Operations of Discrete Types include the function S'Pos(Arg : S'Base), which "returns the position number of the value of Arg, as a value of type universal integer." Hence,
Polarity'Pos(Normal) = 0
Polarity'Pos(Reversed) = 1
You can change the numbering using 13.4 Enumeration Representation Clauses.
...and, of course:
Boolean'Val(Polarity'Pos(Normal)) = False
Boolean'Val(Polarity'Pos(Reversed)) = True
I think what you are looking for is a record type with a representation clause:
procedure Main is
type Byte_T is mod 2**8-1;
for Byte_T'Size use 8;
type Filler7_T is mod 2**7-1;
for Filler7_T'Size use 7;
type Polarity_T is (Normal,Reversed);
for Polarity_T use (Normal => 0, Reversed => 1);
for Polarity_T'Size use 1;
type Byte_As_Record_T is record
Filler : Filler7_T;
Polarity : Polarity_T;
end record;
for Byte_As_Record_T use record
Filler at 0 range 0 .. 6;
Polarity at 0 range 7 .. 7;
end record;
for Byte_As_Record_T'Size use 8;
function Convert is new Ada.Unchecked_Conversion
(Source => Byte_As_Record_T,
Target => Byte_T);
function Convert is new Ada.Unchecked_Conversion
(Source => Byte_T,
Target => Byte_As_Record_T);
begin
-- TBC
null;
end Main;
As Byte_As_Record_T & Byte_T are the same size, you can use unchecked conversion to convert between the types safely.
The representation clause for Byte_As_Record_T allows you to specify which bits/bytes to place your polarity_t in. (i chose the 8th bit)
My definition of Byte_T might not be what you want, but as long as it is 8 bits long the principle should still be workable. From Byte_T you can also safely upcast to Integer or Natural or Positive. You can also use the same technique to go directly to/from a 32 bit Integer to/from a 32 bit record type.
Two points here:
1) Enumerations are already stored as binary. Everything is. In particular, your enumeration, as defined above, will be stored as a 0 for Normal and a 1 for Reversed, unless you go out of your way to tell the compiler to use other values.
If you want to get that value out of the enumeration as an Integer rather than an enumeration value, you have two options. The 'pos() attribute will return a 0-based number for that enumeration's position in the enumeration, and Unchecked_Conversion will return the actual value the computer stores for it. (There is no difference in the value, unless an enumeration representation clause was used).
2) Enumerations are nice, but don't reinvent Boolean. If your enumeration can only ever have two values, you don't gain anything useful by making a custom enumeration, and you lose a lot of useful properties that Boolean has. Booleans can be directly selected off of in loops and if checks. Booleans have and, or, xor, etc. defined for them. Booleans can be put into packed arrays, and then those same operators are defined bitwise across the whole array.
A particular pet peeve of mine is when people end up defining themselves a custom boolean with the logic reversed (so its true condition is 0). If you do this, the ghost of Ada Lovelace will come back from the grave and force you to listen to an exhaustive explanation of how to calculate Bernoulli sequences with a Difference Engine. Don't let this happen to you!
So if it would never make sense to have a third enumeration value, you just name objects something appropriate describing the True condition (eg: Reversed_Polarity : Boolean;), and go on your merry way.
It seems all I needed to do was pragma Pack([type name]); (in which 'type name' is the type composed of Polarity) to compress the value down to a single bit.

Querying with multiple predicates on sub-objects in a collection with MongoDB (official c# driver)

I've the following data structure:
A
_id
B[]
_id
C[]
_id
UserId
I'm trying to run the following query:
where a.B._id == 'some-id' and a.B.C.UserId=='some-user-id'.
That means I need to find a B document that has a C document within with the relevant UserId, something like:
Query.And(Query.EQ("B._id", id), Query.EQ("B.C.UserId", userId));
This is not good, of course, as it may find B with that id and another different B that has C with that UserId. Not good.
How can I write it with the official driver?
If the problem is only that your two predicates on B are evaluated on different B instances ("it may find B with that ID and another different B that has C with that UserId"), then the solution is to use an operator that says "find me an item in the collection that satisfies both these predicates together".
Seems like the $elemMatch operator does exactly that.
From the docs:
Use $elemMatch to check if an element in an array matches the specified match expression. [...]
Note that a single array element must
match all the criteria specified; [...]
You only need to use this when more than 1 field must be matched in the array element.
Try this:
Query.ElemMatch("B", Query.And(
Query.EQ("_id", id),
Query.EQ("C.UserId", userId)
));
Here's a good explanation of $elemMatch and dot notation, which matches this scenario exactly.

VB6 Cast Expression

What is the cast expression equivalent of VB.NET's CType in Visual Basic 6?
There are a number of them depending on the type you are casting to
cint() Cast to integer
cstr() cast to string
clng() cast to long
cdbl() cast to double
cdate() cast to date
It also has implicit casting so you can do this myString=myInt
Quite a few posters seem to have misread the question, so I will try to set things straight by rephrasing the question and summarizing the correct answers given so far.
Problem
I want to cast data of one type to another type. In my VB.NET code I would use CType to do this. However, when I try to use CType in VB6, I get a "Sub or Function not defined" error. So, how can I perform casts in VB6 if CType won't work?
Solution
As you may have discovered, VB6 does not have a CType function like VB.NET does. However, the other conversion functions (those that have names beginning with C), which you may have encountered in VB.NET code, such as CInt and CStr, do exist in VB6, and you can use them to convert to and from non-object types. There is no built-in function for converting an object of one class to an object of another class. Keep in mind that VB6, unlike VB.NET, does not support inheritance. A class in VB6 can implement one or more interfaces, but it cannot inherit from another class. However, if a object's class implements more than one interface, you can use the Set statement to cast an object to one of the interfaces it supports (as Ant suggested). An extended version of Ant's code example is provided below:
Example: Casting a class to one of its supported interfaces
Dim base As BaseClass
Dim child As ChildClass 'implements BaseClass'
Set child = New ChildClass
Set base = child '"Cast" child to BaseClass'
Built-in type conversion functions in VB6
Below is a complete list of the built-in conversion functions available in VB6, taken directly from the VB6 Help file.
CBool
Returns
Boolean
Description
Convert expression to Boolean.
Range for expression argument:
Any valid string or numeric expression.
CByte
Returns
Byte
Description
Convert expression to Byte.
Range for expression argument:
0 to 255.
CCur
Returns
Currency
Description
Convert expression to Currency.
Range for expression argument:
-922,337,203,685,477.5808 to 922,337,203,685,477.5807.
CDate
Returns
Date
Description
Convert expression to Date.
Range for expression argument:
Any valid date expression.
CDbl
Returns
Double
Description
Convert expression to Double.
Range for expression argument:
-1.79769313486232E308 to
-4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values.
CDec
Returns
Decimal
Description
Convert expression to Decimal.
Range for expression argument:
+/-79,228,162,514,264,337,593,543,950,335 for zero-scaled numbers, that is, numbers with no decimal places. For numbers with 28 decimal places, the range is
+/-7.9228162514264337593543950335. The smallest possible non-zero number is 0.0000000000000000000000000001.
CInt
Returns
Integer
Description
Convert expression to Long.
Range for expression argument:
-32,768 to 32,767; fractions are rounded.
CLng
Returns
Long
Description
Convert expression to Long.
Range for expression argument:
-2,147,483,648 to 2,147,483,647; fractions are rounded.
CSng
Returns
Single
Description
Convert expression to Single.
Range for expression argument:
-3.402823E38 to -1.401298E-45 for negative values; 1.401298E-45 to 3.402823E38 for positive values.
CStr
Returns
String
Description
Convert expression to String.
Range for expression argument:
Returns for CStr depend on the expression argument.
CVar
Returns
Variant
Description
Convert expression to Variant.
Range for expression argument:
Same range as Double for numerics. Same range as String for non-numerics.
Let's say you have an object of ChildClass (child) that you want to cast to BaseClass. You do this:
Dim base As BaseClass
Set base = child
Because of the way VB6 handles compile-time type safety, you can just do that without any extra syntax.
Note: Given that everyone else seems to have mentioned CType, I may just have misunderstood the question completely, and I apologise if that's the case!
The casts already mentioned are correct, but if the type is an Object then you have to use "Set" in VB6, such as:
If IsObject(Value) Then
Set myObject = Value ' VB6 does not have CType(Value, MyObjectType)
Else
myObject = Value ' VB6 does not have CType(Value, MyObjectType)
End If
That, of course, depends on the type you are casting to. Almost all user classes are objects as well as Collection, Dictionary, and many others. The built-in types such as long, integer, boolean, etc. are obviously not objects.
Ctype() I believe. The C* (CDate(), CStr(), etc) are holdovers for the most part.
Conversions are not "casts" at all. For example try:
MsgBox CLng(CBool(3&))
The result is -1, not 3. This is because those are conversion functions, not casts. Language is important!

Resources