I'm getting hundreds of errors like:
foo.thing undefined (type Foo has no field or method thing, but does have Thing)
i.e. the fix is very simple, just change foo.thing to foo.Thing.
Is there a way in Go to tell go build to just go ahead and make these changes in mass?
The GoLand refactoring "Rename a code element" might be a good approach.
VSCode rename symbol could help too.
But Go itself does not have that.
There is a backlog feature request for the compilation error message to be more precise (issue 38965)
Instead of (in this example)
./prog.go:11:7: a.B undefined (type A has no field or method B, but does have b)
./prog.go:12:3: a.s undefined (type A has no field or method s, but does have S)
Having the more prescriptive:
./prog.go:11:7: a.B undefined (type A has no field or method B, but does have field b)
./prog.go:12:3: a.s undefined (type A has no field or method s, but does have method S)
CL 232938, May 2020, still pending.
Related
We have some async properties (using #property) and some usual ones. We have to use hy to check if one is async or not using asyncio.iscoroutine function. The problem is we have to use getattr and not . operator, since dot will call the property inner function. We want to change our hy code without breaking the DSL used in other projects, that is, we do not want to use string notation (double quotes) for attribute name and therefore we need to write some macro working just like . but internally calls getattr.
=> (defmacro attr [obj attr] `(getattr ~obj '~attr))
=> (attr 5 real)
Traceback (most recent call last):
File "stdin-5bbedde10a6366314d9be4bd343639582b4d0748", line 1, in <module>
(attr 5 real)
AttributeError: 'int' object has no attribute 'real'
=> (. 5 real)
5
It sounds like you're confused about the semantics of Python properties, which is understandable, since they're rather hairy. In Python (and thus also in Hy for the equivalent constructions), foo.x and getattr(foo, "x") are always equivalent, even if x is a property. To get a property method as an object instead of calling it, you need to retrieve the attribute for the class (type(x)) instead of an instance, and getattr with a string literal and . remain interchangeable. In this example, getattr(type(foo), 'bar').fset could also be written as type(foo).bar.fset.
I tried
(defmacro attr [obj attr]
`(getattr ~obj ~(str attr)))
(print (attr 5 real))
in the web interpreter and it prints 5.
I was unable to reproduce your issue in the web interpreter though. It must still be running an older version, because I had to install your exact version to do it. I suspect that the following breaking change announced for 1.0a2 accounts for the difference:
Hy model objects are no longer equal to ordinary Python values. For
example, (!= 1 '1). You can promote values to models with hy.as-model
before making such a check.
My version of attr does work on Hy 1.0a3. I checked. Try it.
Attributes in Python are stored in the object's .__dict__ using string keys. Since Hy's symbols are no longer equal to strings, the lookup of a string key using a symbol will always fail. Converting the symbol to a string first fixes it. My initial comment was correct. (And this step is unnecessary in Hissp because it lacks Hy's separate model types.)
Although the latter answer works, but I found out that the problem is getting the method behind the property and as #kodiologist wrote, getattr and dot are equivalent. SO I used fget and :
(iscoroutinefunction (.fget (. (type obj) ~attr)))
As per the following screenshot, the TsLint is claiming that a variable might be undefined which is not assignable to a function's parameter.
But I have already checked and make sure that it's not undefined above passing it as the function's parameter.
Why does TsLint is still claiming that the variable might be undefined?
I can dismiss that warning by changing the code to:
clearTimeout(saveDraftTimer.current as unknown as number)
but it looks ugly, any better suggestion?
const saveDraftTimer = useRef<number | undefined>(undefined);
I've been reading some Golang code from github.com/lib/pq which provides drivers for interacting with a postgres database.
Among the code I came across this:
go func() {
select {
case <-done:
_ = cn.cancel()
finished <- struct{}{}
case <-finished:
}
}()
The cancel function looks like:
func (cn *conn) cancel() error
As far as I can tell, the underscore isn't being used as a static assertion about a type (and therefore the compiler doesn't evaluate any side effects as far as I can see (as in this example)) and it isn't a second parameter whereby the author may want to discard it.
In summary: Why assign the result of the cancel function (the error) to an underscore?
Code must be correct. To be sure that code is correct, code must be readable.
The First Rule of Go: Check for errors.
func (cn *conn) cancel() error
If I write
cn.cancel()
did I forget to check for errors or did I decide to discard the error value?
However, if I write
_ = cn.cancel()
I did not forget to check for errors and I did decide to discard the error value.
The Go Programming Language Specification
Blank identifier
The blank identifier is represented by the underscore character _. It
serves as an anonymous placeholder instead of a regular (non-blank)
identifier and has special meaning in declarations, as an operand, and
in assignments.
Assignments
The blank identifier provides a way to ignore right-hand side values
in an assignment:
The blank identifier “_” is a special anonymous identifier. When used in an assignment, like this case, it provides a way to explicitly ignore right-hand side values. So, the developer has decided to ignore/discard the error returned from this method call.
A few reasons why they may have done this (based on a quick glance at the method call and context, my guess is 3 or 4):
The method call is guaranteed to succeed in this context.
The error is already handled sufficiently within the method call; no reason to handle it again.
The error doesn’t matter (eg the relevant process is going to end anyway and the outcome will be the same as if the method call has succeeded without error).
The developer was in a hurry to get something working, ignored the error to save time, then failed to come back and handle the error.
Can I call a block from the XCode debugger? I just tried:
po zoomCurve(0)
Which has the type:
typedef CGFloat (^STAnimationCurveBlock)(CGFloat t);
And the debugger says:
error: called object type 'STAnimationCurveBlock' (aka '__block_literal_generic *') is not a function or function pointer
error: 1 errors parsing expression
As described in this answer, the debugger doesn't seem to know the type of the block. You need to cast the block to its type. In the specific case you have there:
po ((CGFloat(^)(CGFloat))zoomCurve)(0.9)
For some reason, casting to the typdef type also doesn't work, and gives the same error. Specifically, this will give the same error:
po ((STAnimationCurveBlock)zoomCurve)(0.9)
I was just reading through Effective Go and in the Pointers vs. Values section, near the end it says:
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers. This is because pointer methods can modify the receiver; invoking them on a copy of the value would cause those modifications to be discarded.
To test it, I wrote this:
package main
import (
"fmt"
"reflect"
)
type age int
func (a age) String() string {
return fmt.Sprintf("%d yeasr(s) old", int(a))
}
func (a *age) Set(newAge int) {
if newAge >= 0 {
*a = age(newAge)
}
}
func main() {
var vAge age = 5
pAge := new(age)
fmt.Printf("TypeOf =>\n\tvAge: %v\n\tpAge: %v\n", reflect.TypeOf(vAge),
reflect.TypeOf(pAge))
fmt.Printf("vAge.String(): %v\n", vAge.String())
fmt.Printf("vAge.Set(10)\n")
vAge.Set(10)
fmt.Printf("vAge.String(): %v\n", vAge.String())
fmt.Printf("pAge.String(): %v\n", pAge.String())
fmt.Printf("pAge.Set(10)\n")
pAge.Set(10)
fmt.Printf("pAge.String(): %v\n", pAge.String())
}
And it compiles, even though the document says it shouldn't since the pointer method Set() should not be invocable through the value var vAge. Am I doing something wrong here?
That's valid because vAge is addressable. See the last paragraph in Calls under the language spec:
A method call x.m() is valid if the method set of (the type of) x
contains m and the argument list can be assigned to the parameter list
of m. If x is addressable and &x's method set contains m, x.m() is
shorthand for (&x).m().
vAge is not considered as only a "value variable", because it's a known location in memory that stores a value of type age. Looking at vAge only as its value, vAge.Set(10) is not valid as an expression on its own, but because vAge is addressable, the spec declares that it's okay to treat the expression as shorthand for "get the address of vAge, and call Set on that" at compile-time, when we will be able to verify that Set is part of the method set for either age or *age. You're basically allowing the compiler to do a textual expansion on the original expression if it determines that it's necessary and possible.
Meanwhile, the compiler will allow you to call age(23).String() but not age(23).Set(10). In this case, we're working with a non-addressable value of type age. Since it's not valid to say &age(23), it can't be valid to say (&age(23)).Set(10); the compiler won't do that expansion.
Looking at the Effective Go example, you're not directly calling b.Write() at the scope where we know b's full type. You're instead making a temporary copy of b and trying to pass it off as a value of type interface io.Writer(). The problem is that the implementation of Printf doesn't know anything about the object being passed in except that it has promised it knows how to receive Write(), so it doesn't know to take a byteSlice and turn it into a *ByteSlice before calling the function. The decision of whether to address b has to happen at compile time, and PrintF was compiled with the precondition that its first argument would know how to receive Write() without being referenced.
You may think that if the system knows how to take an age pointer and convert it to an age value, that it should be able to do the reverse; t doesn't really make sense to be able to, though. In the Effective Go example, if you were to pass b instead of &b, you'd modify a slice that would no longer exist after PrintF returns, which is hardly useful. In my age example above, it literally makes no sense to take the value 23 and overwrite it with the value 10. In the first case, it makes sense for the compiler to stop and ask the programmer what she really meant to do when handing b off. In the latter case, it of course makes sense for the compiler to refuse to modify a constant value.
Furthermore, I don't think the system is dynamically extending age's method set to *age; my wild guess is that pointer types are statically given a method for each of the base type's methods, which just dereferences the pointer and calls the base's method. It's safe to do this automatically, as nothing in a receive-by-value method can change the pointer anyway. In the other direction, it doesn't always make sense to extend a set of methods that are asking to modify data by wrapping them in a way that the data they modify disappears shortly thereafter. There are definitely cases where it makes sense to do this, but this needs to be decided explicitly by the programmer, and it makes sense for the compiler to stop and ask for such.
tl;dr I think that the paragraph in Effective Go could use a bit of rewording (although I'm probably too long-winded to take the job), but it's correct. A pointer of type *X effectively has access to all of X's methods, but 'X' does not have access to *X's. Therefore, when determining whether an object can fulfill a given interface, *X is allowed to fulfill any interface X can, but the converse is not true. Furthermore, even though a variable of type X in scope is known to be addressable at compile-time--so the compiler can convert it to a *X--it will refuse to do so for the purposes of interface fulfillment because doing so may not make sense.