Cannot init struct in if construct in Go - struct

I got a great surprise when I noticed the following snippet not compiling:
aTime := time.Time{}
if defaultTime := time.Time{} ; aTime != defaultTime {}
The compiler returns:
type time.Time is not an expression
defaultTime := time.Time used as
value undefined: defaultTime
The intent here is to test the aTime variable if it's set to it's default value.
It also does not compile if I get the pointer of the struct (defaultTime := &time.Time{}).
However, it does compile if I init defaultTime outside of the if construct, or do the init using the new() builtin:
aTime := time.Time{}
if defaultTime := new(time.Time) ; aTime != *defaultTime {}
From what I've read everywhere, new(myStruct) it supposed to be completely equivalent to &myStruct{}.
As I interprate it, defaultValue := time.Time{} qualifies as a SimpleStmt (specifically an Assignment), as detailed in the If statement spec.
I've come up with no explanation for this behavior, despite my best googling efforts. Would be grateful if someone could make my head stop spinning.

The { is recognized as the beginning of a Block, terminating the parsing of the SimpleStmt. After committing to that decision, the compiler decides that, as a SimpleStmt, aTime := time.Time isn't valid because time.Time isn't a value that can be assigned. However, it's presumably too late for the parser to try another interpretation of the {.
The version with new works because it doesn't contain a { character, and so avoids confusing the parser in this way.
You can also use the literal format by wrapping it in parentheses, because a block can't legally begin in the middle of an expression, so this also works:
if defaultTime := (time.Time{}); aTime != defaultTime {
// ...
}
gofmt gives the helpful message "expected boolean expression, found simple statement (missing parentheses around composite literal?)", but oddly, the go compiler itself does not.

I don't think what I am going to suggest is necessarily a better solution. But for your use case, you can try this to be concise
if !aTime.IsZero() {
// ...
}
Ymmv

Related

Easy way to get string pointers

A library I am using has a very weird API that often takes string pointers. Currently I am doing this:
s := "foobar"
weirdFun(&s)
to pass strings. Is there a way to do this without the variable?
Maybe you should inform the author of the library, that the strings in Go are already references (to a structure, which is internally represented as a slice of runes), so no expensive copy operation is made by passing string to a function, it's call by reference.
Hope this helps!
The address operation &x can be used with addressable values.
According to the language specification:
The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
So, you can work around this using a composite literal:
package main
import (
"fmt"
)
func main() {
s := "text"
fmt.Printf("value: %v, type: %T\n", &s, &s)
fmt.Printf("value: %v, type: %T\n", &[]string{"literal"}[0], &[]string{"literal"}[0])
}
Even though it's possible I don't recommend using this. This is not an example of clear code.
The Azure SDK uses string pointers to distinguish between no value and the empty string.
Use Azure's StringPtr function to create a pointer to a string literal.
import (
⋮
"github.com/Azure/go-autorest/autorest/to"
)
⋮
res, err := someClient.Create(ctx, someService.ExampleParameters{
Location: to.StringPtr(location),
})
The library is really weird, but
you can do this in one line with function wrap, for example
func PointerTo[T ~string](s T) *T {
return &s
}
s := "string"
weirdFun(PointerTo(s))

How to know if returning an l-value when using `FALLBACK`?

How can I know if I actually need to return an l-value when using FALLBACK?
I'm using return-rw but I'd like to only use return where possible. I want to track if I've actually modified %!attrs or have only just read the value when FALLBACK was called.
Or (alternate plan B) can I attach a callback or something similar to my %!attrs to monitor for changes?
class Foo {
has %.attrs;
submethod BUILD { %!attrs{'bar'} = 'bar' }
# multi method FALLBACK(Str:D $name, *#rest) {
# say 'read-only';
# return %!attrs{$name} if %!attrs«$name»:exists;
# }
multi method FALLBACK(Str:D $name, *#rest) {
say 'read-write';
return-rw %!attrs{$name} if %!attrs«$name»:exists;
}
}
my $foo = Foo.new;
say $foo.bar;
$foo.bar = 'baz';
say $foo.bar;
This feels a bit like a X-Y question, so let's simplify the example, and see if that answers helps in your decisions.
First of all: if you return the "value" of a non-existing key in a hash, you are in fact returning a container that will auto-vivify the key in the hash when assigned to:
my %hash;
sub get($key) { return-rw %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
Please note that you need to use return-rw here to ensure the actual container is returned, rather than just the value in the container. Alternately, you can use the is raw trait, which allows you to just set the last value:
my %hash;
sub get($key) is raw { %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
Note that you should not use return in that case, as that will still de-containerize again.
To get back to your question:
I want to track if I've actually modified %!attrs or have only just read the value when FALLBACK was called.
class Foo {
has %!attrs;
has %!unexpected;
method TWEAK() { %!attrs<bar> = 'bar' }
method FALLBACK(Str:D $name, *#rest) is raw {
if %!attrs{$name}:exists {
%!attrs{$name}
}
else {
%!unexpected{$name}++;
Any
}
}
}
This would either return the container found in the hash, or record the access to the unknown key and return an immutable Any.
Regarding plan B, recording changes: for that you could use a Proxy object for that.
Hope this helps in your quest.
Liz's answer is full of useful info and you've accepted it but I thought the following might still be of interest.
How to know if returning an l-value ... ?
Let's start by ignoring the FALLBACK clause.
You would have to test the value. To deal with Scalars, you must test the .VAR of the value. (For non-Scalar values the .VAR acts like a "no op".) I think (but don't quote me) that Scalar|Array|Hash covers all the l-value super-types:
my \value = 42; # Int is an l-value is False
my \l-value-one = $; # Scalar is an l-value is True
my \l-value-too = #; # Array is an l-value is True
say "{.VAR.^name} is an l-value is {.VAR ~~ Scalar|Array|Hash}"
for value, l-value-one, l-value-too
How to know if returning an l-value when using FALLBACK?
Adding "when using FALLBACK" makes no difference to the answer.
How can I know if I actually need to return an l-value ... ?
Again, let's start by ignoring the FALLBACK clause.
This is a completely different question than "How to know if returning an l-value ... ?". I think it's the core of your question.
Afaik, the answer is, you need to anticipate how the returned value will be used. If there's any chance it'll be used as an l-value, and you want that usage to work, then you need to return an l-value. The language/compiler can't (or at least doesn't) help you make that decision.
Consider some related scenarios:
my $baz := foo.bar;
... (100s of lines of code) ...
$baz = 42;
Unless the first line returns an l-value, the second line will fail.
But the situation is actually much more immediate than that:
routine-foo = 42;
routine-foo is evaluated first, in its entirety, before the lhs = rhs expression is evaluated.
Unless the compiler's resolution of the routine-foo call somehow incorporated the fact that the very next thing to happen would be that the lhs will be assigned to, then there would be no way for a singly or multiply dispatched routine-foo to know whether it can safely return an r-value or must return an l-value.
And the compiler's resolution does not incorporate that. Thus, for example:
multi term:<bar> is rw { ... }
multi term:<bar> { ... }
bar = 99; # Ambiguous call to 'term:<bar>(...)'
I can imagine this one day (N years from now) being solved by a combination of allowing = to be an overloadable operator, robust macros that allow overloading of = being available, and routine resolution being modified so the above ambiguous call could do something equivalent to resolving to the is rw multi. But I doubt it will actually come to pass even with N=10. Perhaps there is another way but I can't think of one at the moment.
How can I know if I actually need to return an l-value when using FALLBACK?
Again, adding "when using FALLBACK" makes no difference to the answer.
I want to track if I've actually modified %!attrs or have only just read the value when FALLBACK was called.
When FALLBACK is called it doesn't know what context it's being called in -- r-value or l-value. Any modification comes after it has already returned.
In other words, whatever solution you come up with will being nothing to do per se with FALLBACK (even if you have to use it to implement some other aspect of whatever it is you're trying to do).
(Even if it were, I suspect trying to solve it via FALLBACK itself would just make matters worse. One can imagine writing two FALLBACK multis, one with an is rw trait, but, as explained above, my imagination doesn't stretch to that making any difference any time soon, if ever, and could only happen if the above imaginary things happened (the macros etc.) and the compiler was also modified to pay attention to the two FALLBACK multi variants, and I'm not at all meaning to suggest that that even makes sense.)
Plan B
Or (alternate plan B) can I attach a callback or something similar to my %!attrs to monitor for changes?
As Lizmat notes, that's the realm of Proxys. And thus your next SO question... :)

Str in XE7 generates strange warning

Why does this code:
w: word;
s: String;
begin
str(w, s);
generate this warning in XE7:
[dcc32 Warning] Unit1.pas(76): W1057 Implicit string cast from 'ShortString' to 'string'
Tom
System.Str is an intrinsic function that dates from a byegone era. The documentation says this:
procedure Str(const X [: Width [:Decimals]]; var S: String);
....
Notes: However, on using this procedure, the compiler may issue a warning: W1057 Implicit string cast from '%s' to '%s' (Delphi).
If a string with a predefined minimum length is not needed, try using the IntToStr function instead.
Since this is an intrinsic, there is likely something extra going on. Behind the scenes, the intrinsic function is implemented by a call to an RTL support function that yields a ShortString. Compiler magic then turns that into a string. And warns you of the implicit conversion. The compiler magic transforms
Str(w, s);
into
s := _Str0Long(w);
Where _Str0Long is:
function _Str0Long(val: Longint): _ShortStr;
begin
Result := _StrLong(val, 0);
end;
Since _Str0Long returns a ShortString then the compiler has to generate code to perform the implicit converstion from ShortString to string when it assigns to your variable s. And of course it's then natural that you see W1057.
The bottom line is that Str only exists to retain compatibility with legacy Pascal ShortString code. New code should not be calling Str. You should do what the documentation says and call IntToStr:
s := IntToStr(w);
Or perhaps:
s := w.ToString;

Global vs local variable valuation issue in Maple

For some reason, the Maple code
testproc := proc()
LOCAL abc;
abc[1] := 123;
print(eval(parse(cat("abc[", 1, "]"))))
end proc
testproc();
produces
abc_1
whereas (same, but with abc now a GLOBAL variable)
testproc := proc()
GLOBAL abc;
abc[1] := 123;
print(eval(parse(cat("abc[", 1, "]"))))
end proc
produces (what I want)
123
What do I need to do so that I can evaluate a concatenated string involving a local variable? Many thanks for any help! :)
When you use parse, it operates as if the text was in its own file or entered at the top level. It doesn't have the context of lexically scoped variables.
You could do something like
eval(parse(cat("abc[",1,"]")),convert('abc',`global`)='abc');
If you want to handle multiple locals, use a set for the second argument to eval.
I assume you have some reason for going through the string form. For straight object manipulation, it isn't usually a good idea.

Smalltalk - Compare two strings for equality

I am trying to compare two strings in Smalltalk, but I seem to be doing something wrong.
I keep getting this error:
Unhandled Exception: Non-boolean receiver. Proceed for truth.
stringOne := 'hello'.
stringTwo := 'hello'.
myNumber := 10.
[stringOne = stringTwo ] ifTrue:[
myNumber := 20].
Any idea what I'm doing wrong?
Try
stringOne = stringTwo
ifTrue: [myNumber := 20]`
I don't think you need square brackets in the first line
Found great explanation. Whole thing is here
In Smalltalk, booleans (ie, True or False) are objects: specifically, they're instantiations of the abstract base class Boolean, or rather of its two subclasses True and False. So every boolean has type True or False, and no actual member data. Bool has two virtual functions, ifTrue: and ifFalse:, which take as their argument a block of code. Both True and False override these functions; True's version of ifTrue: calls the code it's passed, and False's version does nothing (and vice-versa for ifFalse:). Here's an example:
a < b
ifTrue: [^'a is less than b']
ifFalse: [^'a is greater than or equal to b']
Those things in square brackets are essentially anonymous functions, by the way. Except they're objects, because everything is an object in Smalltalk. Now, what's happening there is that we call a's "<" method, with argument b; this returns a boolean. We call its ifTrue: and ifFalse: methods, passing as arguments the code we want executed in either case. The effect is the same as that of the Ruby code
if a < b then
puts "a is less than b"
else
puts "a is greater than or equal to b"
end
As others have said, it will work the way you want if you get rid of the first set of square brackets.
But to explain the problem you were running into better:
[stringOne = stringTwo ] ifTrue:[myNumber := 20]
is passing the message ifTrue: to a block, and blocks do not understand that method, only boolean objects do.
If you first evaluate the block, it will evaluate to a true object, which will then know how to respond:
[stringOne = stringTwo] value ifTrue:[myNumber := 20]
Or what you should really do, as others have pointed out:
stringOne = stringTwo ifTrue:[myNumber := 20]
both of which evaluates stringOne = stringTwo to true before sending ifTrue:[...] to it.
[stringOne = stringTwo] is a block, not a boolean. When the block is invoked, perhaps it will result in a boolean. But you are not invoking the block here. Instead, you are merely causing the block to be the receiver of ifTrue.
Instead, try:
(stringOne = stringTwo) ifTrue: [
myNumber := 20 ].
Should you be blocking the comparison? I would have thought that:
( stringOne = stringTwo ) ifTrue: [ myNumber := 20 ]
would be enough.
but I seem to be doing something wrong
Given that you are using VisualWorks your install should include a doc folder.
Look at the AppDevGuide.pdf - it has a lot of information about programming with VisualWorks and more to the point it has a lot of introductory information about Smalltalk programming.
Look through the Contents table at the beginning, until Chapter 7 "Control Structures", click "Branching" or "Conditional Tests" and you'll be taken to the appropriate section in the pdf that tells you all about Smalltalk if-then-else and gives examples that would have helped you see what you were doing wrong.
I would like to add the following 50Cent:
as blocks are actually lambdas which can be passed around, another good example would be the following method:
do:aBlock ifCondition:aCondition
... some more code ...
aCondition value ifTrue: aBlock.
... some more code ...
aBlock value
...
so the argument to ifTrue:/ifFalse: can actually come from someone else. This kind of passed-in conditions is often useful in "..ifAbsent:" or "..onError:" kind of methods.
(originally meant as a comment, but I could not get the code example to be unformatted)

Resources