In this simple code example...
fun testLocalFunctions() {
aLocalFun() //compiler error: unresolved reference at aLocalFun
fun aLocalFun() {}
aLocalFun() //no error
}
Elsewhere in the language, using a function before definition is allowed. But for local functions, that does not appear to be the case. Refering to the Kotlin Language Specification, the section on Local Functions is still marked "TODO".
Since this sort of constraint does not hold for other types of functions (top-level and member functions), is this a bug?
(Granted, local variable declarations must occur before use, so the same constraint on local functions is not unreasonable. Is there a definitive, preferably authoritative source document that discusses this behavior?)
It's not a bug, it is the designed behavior.
When you use a symbol (variable, type or function name) in an expression, the symbol is resolved against some scope. If we simplify the scheme, the scope is formed by the package, the imports, the outer declarations (e.g. other members of the type) and, if the expression is placed inside a function, the scope also includes the local declarations that precede the expression.
So, you can't use a local function until it's declared just like you cannot use a local variable that is not declared up to that point: it's just out of scope.
Related
Can I only define functions in Modules?
I load some of the Table inside the Module, for example,
Bar_1m = loadTable bar_1m
"the DFS: // Kline", "bar_1m" , but in the use of this module, when I references after bar_1m, the system will complain Variable'bar_1m' is not initialized yet.
In the module file, only encapsulated function definitions are allowed, and other non-function definition codes will be ignored
An important part of OOP is to use access specifiers to make member methods and variables inaccessible from outside of the object.
When declaring a function block method is is easy to control the Access Specifier, but I have not found a way to control access to member variables.
Is it possible and if yes, how?
You can actually still access internal variables of an object direcly in code (no pointers), but they are read only. The code completion will not display the internal variables though, but after you finish typing the name structure, you will see no compile errorrs - test := fb1.internalVariable will be a valid read action actually while fb1.internalVariable := 5; will end up giving you an error, saying that the variable is not an input to the function block (or any other object for that matter).
You can also use the hide oder hide_all_locals pragma to suppress local variables being found in auto-complete and crossreference-list (see https://infosys.beckhoff.com/content/1033/tc3_plc_intro/2529654667.html?id=5927203996458905204 )
Every variable that you declare under the VAR section of your Function Block is considered private.
There is no public or private keyword for variables in IEC 61131-3
Another thing you can do if you absolutely want to use public/private keywords is to define properties.
In general, the normal convention is to have read-only variables in the VAR_OUTPUT section of the Function Block and writable variables in the VAR_INPUT section of the Function Block. Again, the VAR section is considered a private section even though you could read this variables with the fbName.var notation or write them through their address (but this is a very bad programming style).
Twincat2 also allowed the variables in the VAR section to be written to with the fbName.var notation but this changed in Twincat3 in order to achieve better incapsulation.
To learn more about programming conventions in the IEC 61131-3 world, I recommend you to read the programming guidelines of the PLCOpen organization:
https://plcopen.org/guidelines/guidelines
fun myfunction(a:String) //this is valid
fun myfunction(var a:String) //this is invalid
fun myfunction(val a:String) //this is invalid
The support for var was removed way back from kotlin with the following reason:
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime). Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing if a function declarations (namely, it creates a property). Also, we all know that mutating parameters is no good style, so writing “val” or “var” infront of a parameter in a function, catch block of for-loop is no longer allowed.
More details in https://blog.jetbrains.com/kotlin/2013/02/kotlin-m5-1/.
According to the Kotlin docs on destructuring declarations, the declared components should match the number of components on the right side:
Anything can be on the right-hand side of a destructuring declaration, as long as the required number of component functions can be called on it.
However, I discovered that this works even if the left hand side doesn't have the same number of components as on the right side of the assignment statement.
fun main() {
val (firstOnly) = Pair("key", "value")
println("firstOnly=${firstOnly}")
}
Is this legal Kotlin or is this is a bug? If it's legal, is there a reference?
If it's legal, is there a reference?
The Kotlin Language Specification says:
A special case of definition by convention is the destructuring declaration of properties [...]
This convention allows to introduce a number (one or more) of properties in the place of one by immediately destructuring the property during construction.
It says "one or more", so yes, declaring a single property by destructuring is allowed.
Also note that "required number of component functions can be called on it" doesn't mean the number of component functions has to equal to number of properties being declared. Let's put it this way: if I have 2 apples, and 1 apple is required. Do I have the "required number of apples"? Clearly the answer is yes.
If you still find it unclear, I think the spec says it better:
For each identifier the corresponding operator function componentK with
K being equal to the position of the placeholder in the declaration (starting from 1) is called without arguments.
which implies that those functions calls need to be valid. Whether or not other component functions exist is not relevant.
From the document you linked to:
Anything can be on the right-hand side of a destructuring declaration, as long as the required number of component functions can be called on it.
It doesn't say it has to match the number of variables declared on the left, only that it has the required number.
In fact, this is very useful when destructuring a List:
val (first, second) = listOf(1, 2, 3, 4, 5)
The documentation for List<T>.component1():
Throws an IndexOutOfBoundsException if the size of this list is less than 1.
Again, it doesn't restrict the list to being of size 1.
I came across an example for a C-function declared as:
static inline CGPoint SOCGPointAdd(const CGPoint a, const CGPoint b) {
return CGPointMake(a.x + b.x, a.y + b.y);
}
Until now, I declared utility C-functions in .h files and implemented them in .m files, just like this:
CGPoint SOCGPointAdd(const CGPoint a, const CGPoint b) {
return CGPointMake(a.x + b.x, a.y + b.y);
}
I can use this function "inline" anywhere I want and it should also be "static" because it's not associated with any object, like an Objective-c method. What is the point / advantage of specifying "static" and "inline"?
inline does not mean you can use the function “inline” (it is normal to use functions inside other functions; you do not need inline for that); it encourages the compiler to build the function into the code where it is used (generally with the goal of improving execution speed).
static means the function name is not externally linked. If the function were not declared static, the compiler is required to make it externally visible, so that it can be linked with other object modules. To do this, the compiler must include a separate non-inline instance of the function. By declaring the function static, you are permitting all instances of it to be inlined in the current module, possibly leaving no separate instance.
static inline is usually used with small functions that are better done in the calling routine than by using a call mechanism, simply because they are so short and fast that actually doing them is better than calling a separate copy. E.g.:
static inline double square(double x) { return x*x; }
If the storage class is extern, the identifier has external linkage and the inline definition also provides the external definition. If the storage class is static, the identifier has internal linkage and the inline definition is invisible in other translation units.
By declaring a function inline, you can direct the compiler to integrate that function's code into the code for its callers (to replace the complete code of that function directly into the place from where it was called). This makes execution faster by eliminating the function-call overhead. That's why inline functions should be very short.
In C, inline means that it is an inline definition. It doesn't have internal linkage, it has no linkage. It never reaches the linker, which means that if the compiler doesn't use that inline definition to inline every single reference to the function in the compilation unit, then there will be a local linker error if a symbol with the same name (C uses unmangled identifiers) with external linkage is not exported by another translation unit in the compilation. The actual inlining of references to the function by the compiler is exclusively controlled by the optimisation flag or __attribute__((always_inline))
There is no difference between static inline and static, both do not inline the function, and provide the function in the assembly output on -O0 as an internal linkage symbol to the linker, and both inline and optimise out the inclusion of the function in the assembly output on -O1. static inline does have one quirk in that you can use a non-static inline prototype before it, except this prototype is ignored and isn't used as a forward declaration (but using a non-static prototype before a static function is an error).
inline (GCC <5.0, which used -std=gnu90 / gnu89 as default) / extern inline (GCC 5.0 onwards, which uses -std=gnu11): This is a compiler only inline definition. Externally visible function emittance (in the assembly output for use of the assembler and linker) for this inline definition does not occur. If all references to the function in the file are not actually inlined by the compiler (and inlining occurs on higher optimisation levels or if you use __attribute__((always_inline)) inline float func()), then there will be a local linker error if the compiler does not emit the external definition to the linker (and if a symbol with the same name with external linkage is not exported by another translation unit). This allows for an inline definition and an out-of-line function of the same symbol to be defined separately, one with inline and the other out-of-line, but not in the same translation unit as the compiler will confuse them, and an out of line definitition will be treated as a redefinition error. Inline definitions are only ever visible to the compiler and each translation unit can have their own. Inline definitions cannot be exported to other files because inline definitions do not reach the linking stage. In order to achieve this at compile-time, the inline definition can be in a header file and included in each translation unit. This means that the use of inline is a compiler directive and extern/static refer to the out-of-line version produced for the linker. If the function is not defined in the translation unit, it cannot be inlined because it's left to the linker. If the function is defined but not inline, then the compiler will use this version if it decides to inline
extern inline (GCC <5.0) / inline (GCC >5.0): an externally visible function is emitted for this inline definition regardless of whether it is inlined or not meaning this specifier can only be used in one of the translation units. This is intuitively the opposite of 'extern'
static inline: locally visible out-of-line function is emitted by the compiler to the assembly output with a local directive for the assembler for this compiler inline definition, but may be optimised out on higher optimisation levels if all the functions are able to be inlined; it will never allow a linker error to result. It behaves identically to static because the compiler will inline the static definition on higher optimisation levels just like static inline.
An inline function that isn't static shouldn't contain non-const static storage duration variables or access static file-scope variables, this will produce a compiler warning. This is because the inline and out-of-line versions of the function will have distinct static variables if the out-of-line version is provided from a different translation unit. The compiler may inline some functions, not emit a local symbol to be linked to those references, and leave the linkage to the linker which might find an external function symbol, which is assumed to be the same function as it has the same identifier. So it reminds the programmer that it should logically be const because modifying and reading the static will result in undefined behaviour; if the compiler inlines this function reference, it will read a fresh static value in the function rather than the one written to in a previous call to the function, where that previous reference to the function was one that wasn't inlined, hence the variable that was written to in the previous call would have been one provided by a different translation unit. In this instance, it results in a copy local to each translation unit and a global copy and it is undefined as to which copy is being accessed. Making it const ensures that all the copies are identical and will never change with respect to each other, making the behaviour defined and known.
Using an inline / extern inline prototype before/after a non-inline definition means that the prototype is ignored.
Using an inline prototype before an inline definition is how to prototype an inline function without side effects, declaring an inline prototype after the inline definition changes nothing unless the storage specifier changes.
Using an extern inline / extern / regular prototype before/after an inline definition is identical to an extern inline definition; it is a hint that provides an external out-of-line definition of the function, using the inline definition.
Using extern inline / inline on a prototype without a definition in the file but it is referenced in the file results in inline being ignored an then it behaves as a regular prototype (extern / regular, which are identical)
Using a static inline / static on a prototype without a definition in the file but it is referenced in the file results in correct linkage and correct type usage but a compiler warning saying that the function with internal linkage has not been defined (so it uses an external definition)
Using a regular / extern / extern inline prototype before a static inline or static definition is a 'static declaration of 'func' follows non-static declaration' error; using it after does nothing and they are ignored. Using a static or static inline prototype before/after a static inline definition is allowed. Using an inline prototype before a static inline definition is ignored and will not act as a forward declaration. This is the only way in which static inline differs from static as a regular prototype before a static definition results in an error, but this does not.
Using a static inline prototype before a regular / extern / static / static inline / extern inline definition results in static inline overriding the specifiers and acts as correctly as a forward declaration.
__attribute__((always_inline)) always inlines the function symbol in the translation unit, and uses this definition. The attribute can only be used on definitions. The storage / inline specifiers are unaffected by this and can be used with it.
Inline functions are for defining in header files.Small functions are defined in header files.
It should be static so that it can acess only static members.