How to declare data type ENUM in Yaskawa MotionWorks IEC 3? - enums

I'm trying to add my own enum in MotionWorks.
After creation of new data type the only available types are ARRAY,STRING,STRUCT.
Writing the following code:
TYPE SimulationType:
(
Passing := 0,
Random := 1,
Failing := 2
) INT := 0;
END_TYPE
does not compile.
Yaskawa seem to be complying to ENUM (according to this list) but I can't figure out how to declare it.
Edit:
I can do the following:
TYPE
ResultType:(Pass, Random, Fail);
END_TYPE
But it doesn't seem to create an enum, as I can't access it's value. I can access it like a structure.
Edit 2:
If I declare:
TYPE
ResultType:(Pass, Random, Fail);
END_TYPE
And set variable
ExpectedResultType : ResultType;
Then in the code I try to use:
IF ExpectedResultType = ResultType.Pass THEN
Done := TRUE;
END_IF;
It compiles, but will not run.
Trying to use this code will not compile:
CASE ExpectedResultType OF
ResultType.Pass:
Done := TRUE;
Error := FALSE;
ResultType.Random:
Done := TRUE;
ResultType.Fail:
Error := TRUE;
Done := FALSE;
END_CASE;

Enums in MotionWorks are declared in data types as this example:
TYPE
MyEnum:(Zero,One,Two,Three);
END_TYPE
ENUMs in MotionWorks can't be assigned a value. First enum will always be equal to 0 (zero), second one to 1 (one), and so on.
Then enums can be used in IF .. END_IF statements like this:
I'll call my variable "i". The variable must be declared as INT. Any other type will not work.
In the code use it like this:
IF i = MyEnum#Zero THEN
(* do some work *)
ELSIF i = MyEnum#One THEN
(* do some other work *)
END_IF
ENUMs can't be used in CASE statements in MotionWorks.

This what I have for Schneider which is IEC61131 so it should be the same
TYPE E_HomeLimitSwitch:
(
ePositiveDirectionRisingEdge := 0,
eNegativeDirectionRisingEdge := 1,
ePositiveDirectionFallingEdge := 2,
eNegativeDirectionFallingEdge := 3
);
END_TYPE
I don't think you INT:=0 should be there.

You can only set the default value to one of your local enum members. Not to other values or even a number as you tried.
Try this instead in line 6:
) INT := Passing;

unlike Codesys, Yaskawa's MotionWorksIEC does not fully support enumerations. In ST language enum usage is quite popular in CASE statements but MotionWorksIEC does not support enum use in case statements.
But, you still can define enums as shown below.
TYPE
PackMLState:(Starting,Starting,Aborting,Aborted,Helding,Held,Etc);
END_TYPE
You can use the enum type as;
IF machineState = PackMLState#Starting THEN
;;
END_IF
Comparing Codesys and MotionWorksIEC (Which is basically Phoenix Contact, KW Software Multiprog), there are some differences. For clarification, the lack of enum use in Cases doesn't make Multiprog an inferior IDE.

Related

Is there a way to extract a protobuf oneof int value?

TL;DR: In Go, is there any way to get the integer value of a protobuf oneof case?
Detail:
In C# I can easily query the integer value of a Oneof case using something like the following:
opcode = (int)ChannelMessage.ChannelActionOneofCase.Register; // opcode will equal 1
However in Golang, there does not appear to be anything that I can use to easily extract that integer value.
I know that I can switch on the type itself:
switch m.ChannelAction.(type) {
case *proto.ChannelMessage_Register:
...
however in my case this will require me to unmarshal every message, which for certain types isn't strictly necessary since I'm required to send the opcode along every time.
If it's helpful, my ChannelMessage type looks like the following:
message ChannelMessage
{
oneof ChannelAction
{
ChannelRegister register = 1;
ChannelUnregister unregister = 2;
...
}
}
It's probably not what you want to actually do, but the google.golang.org/protobuf/reflect/protoreflect package does have the necessary functions, if you need to refer to the field numbers of the fields that are part of your oneof.
For example, assuming you've imported your protos as pb, to get the number 1 by name (as in your C# example) you can do:
desc := (&pb.ChannelMessage{}).ProtoReflect().Descriptor()
opcode := desc.Fields().ByName("register").Number()
(This isn't strictly specific to the oneof, since oneof fields are really just regular message fields with an additional constraint that only one of them may be set.)
Or to figure out which field number a oneof field is set to in message m without writing out a type switch, assuming you know one of them has definitely been set, you can do:
ref := m.ProtoReflect()
desc := ref.Descriptor()
num := ref.WhichOneof(desc.Oneofs().ByName("ChannelAction")).Number()
In both cases the result (opcode, num) will be a numeric type (protoreflect.FieldNumber = protowire.Number) that has an underlying type of int32 you can convert it to.
You are right, you can do that with type switch:
// my example used simple strings instead of custom messages.
example := proto.ChannelMessage{
ChannelAction: &pbExample.ChannelMessage_Register{"foobar"},
}
t := example.GetChannelAction()
switch v := t.(type) {
case *pbExample.ChannelMessage_Register:
fmt.Printf("register\n")
case *pbExample.ChannelMessage_Unregister:
fmt.Printf("unregister\n")
default:
fmt.Printf("I don't know about type %T!\n", v)
}
// what you also can do is to ask directly your oneOf case and try to typecast it.
val, ok := example.GetRegister().(int) // GetUnregister is other option.
if ok {
// black magic happens here
}

Assertion of zero int to int32

I noticed that Go assertion doesn't work as I expect for zero int. Here is the code:
var i interface{}
i = 0
i32, ok := i.(int32)
fmt.Println(ok)
fmt.Println(i32)
The output is following:
false
0
I can't find an explanation of this behavior. Is it a bug?
i doesn't contain an int32, it contains an int, and so the type assertion fails.
Assigning a literal value directly to an interface{} like this or using one in a short variable declaration can be a bit confusing because you don't really get to see what type of value you get; you need to know the rules for the "default type" of a constant. If this gives you trouble, you can explicitly cast it to a type, like
i = int32(0), which will ensure that i does in fact contain an int32.
No, it's not a bug, it's a well defined behavior.
This line:
i = 0
Is an assignment, and you use the untyped 0 integer constant to assign to i. Since a (concrete) type is needed to carry out the assignment (and is type being interface{} does not define one), the default type of that untyped constant will be used which is int. Read The Go Blog: Constants:
The answer is that an untyped constant has a default type, an implicit type that it transfers to a value if a type is needed where none is provided.
You can verify it if you modify it like this:
i2, ok := i.(int)
fmt.Println(ok)
fmt.Println(i2)
Which outputs:
true
0
If you would use a typed constant:
i = int32(0)
Then yes, the stored value would be of type int32, and you would get the same output:
i = int32(0)
i32, ok := i.(int32)
fmt.Println(ok)
fmt.Println(i32)
Try the examples on the Go Playground.

What the purpose of function-like initialization for builtin types in go?

I know, go converts right side untyped constant to left side typed variable right after := initialization in expression: a := 5.
And it looks like the same as b := int(5) statement. So, what is the purpose of the second statement and how it differs from the first one?
Also, somewhere, I have seen []int(nil) expression, that's a bit confuse me.
Generally you don't need to use := in combination with a type conversion because it defeats the point of :=. := is there to infer the type. The type can generally be inferred from a constant value.
But not always. For example...
package main
import (
"fmt"
)
func main() {
a := 5
b := uint(5)
var c uint = 5
fmt.Printf("%T\n", a)
fmt.Printf("%T\n", b)
fmt.Printf("%T\n", c)
}
a := 5 infers that a is of type int, but what if you wanted it to be something else? 5 could be a bunch of different integer types. Maybe an unsigned integer? Maybe an integer of a specific length like int16?
You can do this by either specifying the type of the constant explicitly, as in b := uint(8), or by specifying the type of the variable explicitly, as in var c uint = 8. With b := uint(8), b's type is inferred from the uint constant being assigned to it. With var c uint = 8, 8 is inferred to be an unsigned integer because it is being assigned to a variable with the type uint. In both cases, b and c will be of type uint.
I'm not aware of any significant difference between b := uint(8) and var b uint = 8, so which you use is largely up to taste. I have a slight preference for var b uint = 8 because it is visually distinct from b := 8 to make it clear explicit types are being used.
You are referring to a type conversion. A type conversion is used to convert a value of one type to a value of another type.
The expression int(5) converts the untyped 5 to an int with value 5.
The expression []int(nil) converts the untyped nil to a []int with value nil.
The statements
a := 5
b := int(5)
declare a int variable with value 5. The declaration of a uses the default type for integer constants (which is int). The declaration of b explicitly uses the int type. Otherwise, they are the same. The use of the default type in the declaration of a is usually preferred over the explicit type in the declaration of b. The type conversion is commonly used for types other than the default type. Example c := int64(22).

Go, is this everything you need to know for assignments and initialization?

It is just mind boggling how many different ways Go has for variable initialization. May be either i don't understand this completely or Go is a big after thought. Lot of things don't feel natural and looks like they added features as they found them missing. Initialization is one of them.
Here is running app on Go playground showing different ways of initialization
Here is what i understand
There are values and pointers. Values are initiated using var = or :=.
:= only works inside the methods
To Create value and reference you use new or &. And they only work on composite types.
There are whole new ways of creating maps and slices
Create slice and maps using either make or var x []int. Noticing there is no = or :=
Are there any easy way to understand all this for newbies? Reading specs gives all this in bits and pieces everywhere.
First, to mention some incorrect statements:
To Create value and reference you use new or &. And they only work on composite types.
new() works on everything. & doesn't
Create slice and maps using either make or var x []int. Noticing there is no = or :=
You can actually use := with x := []int{} or even x := []int(nil). However, the first is only used when you want to make a slice of len 0 that is not nil and the second is never used because var x []int is nicer.
Lets start from the beginning. You initialize variables with var name T. Type inference was added because you can type less and avoid worrying about the name of a type a function returns. So you are able to do var name = f().
If you want to allocate a pointer, you would need to first create the variable being pointed to and then get its pointer:
var x int
var px = &x
Requiring two statements can be bothersome so they introduced a built-in function called new(). This allows you to do it in one statement: var px = new(int)
However, this method of making new pointers still has an issue. What if you are building a massive literal that has structs that expect pointers? This is a very common thing to do. So they added a way (only for composite literals) to handle this.
var x = []*T{
&T{x: 1},
&T{x: 2},
}
In this case, we want to assign different values to fields of the struct the pointers reference. Handling this with new() would be awful so it is allowed.
Whenever a variable is initialized, it is always initialized to its zero value. There are no constructors. This is a problem for some of the builtin types. Specifically slices, maps, and channels. These are complicated structures. They require parameters and initialization beyond memory being set to zero. Users of Go who need to do this simply write initialization functions. So, that is what they did, they wrote make(). neW([]x) returns a pointer to a slice of x while make([]x, 5) returns a slice of x backed by an array of length 5. New returns a pointer while make returns a value. This is an important distinction which is why it is separate.
What about :=? That is a big clusterfuck. They did that to save on typing, but it led to some odd behaviors and the tacked on different rules until it became somewhat usable.
At first, it was a short form of var x = y. However, it was used very very often with multiple returns. And most of those multiple returns were errors. So we very often had:
x, err := f()
But multiple errors show up in your standard function so people started naming things like:
x, err1 := f()
y, err2 := g()
This was ridiculous so they made the rule that := only re-declares if it is not already declared in that scope. But that defeats the point of := so they also tacked on the rule that at least one must be newly declared.
Interestingly enough, this solves 95% of its problems and made it usable. Although the biggest problem I run into with it is that all the variables on the lefthand side must be identifiers. In other words, the following would be invalid because x.y is not an identifier:
x.y, z := f()
This is a leftover of its relation to var which can't declare anything other than an identifier.
As for why := doesn't work outside a function's scope? That was done to make writing the compiler easier. Outside a function, every part starts with a keyword (var, func, package, import). := would mean that declaration would be the only one that doesn't start with a keyword.
So, that is my little rant on the subject. The bottom line is that different forms of declaration are useful in different areas.
Yeah, this was one of those things that I found confusing early as well. I've come up with my own rules of thumb which may or may not be best practices, but they've served me well. Tweaked after comment from Stephen about zero values
Use := as much as possible, let Go infer types
If you just need an empty slice or map (and don't need to set an initial capacity), use {} syntax
s := []string{}
m := map[string]string{}
The only reason to use var is to initialize something to a zero value (pointed out by Stephen in comments) (and yeah, outside of functions you'll need var or const as well):
var ptr *MyStruct // this initializes a nil pointer
var t time.Time // this initializes a zero-valued time.Time
I think your confusion is coming from mixing up the type system with declaration and initialization.
In Go, variables can be declared in two ways: using var, or using :=. var only declares the variable, while := also assigns an initial value to it. For example:
var i int
i = 1
is equivalent to
i := 1
The reason this is possible is that := simply assumes that the type of i is the same as the type of the expression it's being initialized to. So, since the expression 1 has type int, Go knows that i is being declared as an integer.
Note that you can also explicitly declare and initialize a variable with the var keyword as well:
var i int = 1
Those are the only two delcaration/initialization constructs in Go. You're right that using := in the global scope is not allowed. Other than that, the two are interchangable, as long as Go is able to guess what type you're using on the right-hand-side of the := (which is most of the time).
These constructs work with any types. The type system is completely independent from the declaration/initialization syntax. What I mean by that is that there are no special rules about which types you can use with the declaration/initialization syntax - if it's a type, you can use it.
With that in mind, let's walk through your example and explain everything.
Example 1
// Value Type assignments [string, bool, numbers]
// = & := Assignment
// Won't work on pointers?
var value = "Str1"
value2 := "Str2"
This will work with pointers. The key is that you have to be setting these equal to expressions whose types are pointers. Here are some expressions with pointer types:
Any call to new() (for example, new(int) has type *int)
Referencing an existing value (if i has type int, then &i has type *int)
So, to make your example work with pointers:
tmp := "Str1"
var value = &tmp // value has type *int
value2 := new(string)
*value2 = "Str2"
Example 2
// struct assignments
var ref1 = refType{"AGoodName"}
ref2 := refType{"AGoodName2"}
ref3 := &refType{"AGoodName2"}
ref4 := new(refType)
The syntax that you use here, refType{"AGoodName"}, is used to create and initialize a struct in a single expression. The type of this expression is refType.
Note that there is one funky thing here. Normally, you can't take the address of a literal value (for example, &3 is illegal in Go). However, you can take the address of a literal struct value, like you do above with ref3 := &refType{"AGoodName2"}. This seems pretty confusing (and certainly confused me at first). The reason it's allowed is that it's actually just a short-hand syntax for calling ref3 := new(refType) and then initializing it by doing *ref3 = refType{"AGoodName2"}.
Example 3
// arrays, totally new way of assignment now, = or := now won't work now
var array1 [5]int
This syntax is actually equivalent to var i int, except that instead of the type being int, the type is [5]int (an array of five ints). If we wanted to, we could now set each of the values in the array separately:
var array1 [5]int
array1[0] = 0
array1[1] = 1
array1[2] = 2
array1[3] = 3
array1[4] = 4
However, this is pretty tedious. Just like with integers and strings and so on, arrays can have literal values. For example, 1 is a literal value with the type int. The way you create a literal array value in Go is by naming the type explicitly, and then giving the values in brackets (similar to a struct literal) like this:
[5]int{0, 1, 2, 3, 4}
This is a literal value just like any other, so we can use it as an initializer just the same:
var array1 [5]int = [5]int{0, 1, 2, 3, 4}
var array2 = [5]int{0, 1, 2, 3, 4}
array3 := [5]int{0, 1, 2, 3, 4}
Example 4
// slices, some more ways
var slice1 []int
Slices are very similar to arrays in how they are initialized. The only difference is that they aren't fixed at a particular length, so you don't have to give a length parameter when you name the type. Thus, []int{1, 2, 3} is a slice of integers whose length is initially 3 (although could be changed later). So, just like above, we can do:
var slice1 []int = []int{1, 2, 3}
var slice2 = []int{1, 2, 3}
slice3 := []int{1, 2, 3}
Example 5
var slice2 = new([]int)
slice3 := new([]int)
Reasoning about types can get tricky when the types get complex. As I mentioned above, new(T) returns a pointer, which has type *T. This is pretty straightforward when the type is an int (ie, new(int) has type *int). However, it can get confusing when the type itself is also complex, like a slice type. In your example, slice2 and slice3 both have type *[]int. For example:
slice3 := new([]int)
*slice3 = []int{1, 2, 3}
fmt.Println((*slice3)[0]) // Prints 1
You may be confusing new with make. make is for types that need some sort of initialization. For slices, make creates a slice of the given size. For example, make([]int, 5) creates a slice of integers of length 5. make(T) has type T, while new(T) has type *T. This can certainly get confusing. Here are some examples to help sort it out:
a := make([]int, 5) // s is now a slice of 5 integers
b := new([]int) // b points to a slice, but it's not initialized yet
*b = make([]int, 3) // now b points to a slice of 5 integers
Example 6
// maps
var map1 map[int]string
var map2 = new(map[int]string)
Maps, just like slices, need some initialization to work properly. That's why neither map1 nor map2 in the above example are quite ready to be used. You need to use make first:
var map1 map[int]string // Not ready to be used
map1 = make(map[int]string) // Now it can be used
var map2 = new(map[int]string) // Has type *map[int]string; not ready to be used
*map2 = make(map[int]string) // Now *map2 can be used
Extra Notes
There wasn't a really good place to put this above, so I'll just stick it here.
One thing to note in Go is that if you declare a variable without initializing it, it isn't actually uninitialized. Instead, it has a "zero value." This is distinct from C, where uninitialized variables can contain junk data.
Each type has a zero value. The zero values of most types are pretty reasonable. For example, the basic types:
int has zero value 0
bool has zero value false
string has zero value ""
(other numeric values like int8, uint16, float32, etc, all have zero values of 0 or 0.0)
For composite types like structs and arrays, the zero values are recursive. That is, the zero value of an array is an array with all of its entries set to their respective zero values (ie, the zero value of [3]int is [3]int{0, 0, 0} since 0 is the zero value of int).
Another thing to watch out for is that when using the := syntax, certain expressions' types cannot be inferred. The main one to watch out for is nil. So, i := nil will produce a compiler error. The reason for this is that nil is used for all of the pointer types (and a few other types as well), so there's no way for the compiler to know if you mean a nil int pointer, or a nil bool pointer, etc.

What does := mean in Go?

I'm following this tutorial, specifically exercise 8:
http://tour.golang.org/#8
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
Specifically what does the := mean? Searching for Go documentation is very hard, ironically.
A short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
It is a shorthand for a regular variable declaration with initializer expressions but no types:
Keep on going to page 12 of the tour!
A Tour of Go
Short variable declarations
Inside a function, the := short assignment statement can be used in
place of a var declaration with implicit type.
(Outside a function, every construct begins with a keyword and the :=
construct is not available.)
As others have explained already, := is for both declaration, and assignment, whereas = is for assignment only.
For example, var abc int = 20 is the same as abc := 20.
It's useful when you don't want to fill up your code with type or struct declarations.
The := syntax is shorthand for declaring and initializing a variable, example f := "car" is the short form of var f string = "car"
The short variable declaration operator(:=) can only be used for declaring local variables. If you try to declare a global variable using the short declaration operator, you will get an error.
Refer official documentation for more details
:= is not an operator. It is a part of the syntax of the Short variable declarations clause.
more on this: https://golang.org/ref/spec#Short_variable_declarations
According to my book on Go, it is just a short variable declaration statement
exactly the same as
var s = ""
But it is more easy to declare, and the scope of it is less expansive. A := var decleration also can't have a type of interface{}. This is something that you will probably run into years later though
:= represents a variable, we can assign a value to a variable using :=.

Resources