Forward declarations in CapnProto - capnproto

In a CapnProto schema is there any way to forward-declare structs so you can make a tree structure like this:
struct ExecuteProgram {
code #0 :Text;
}
struct SequenceProgram {
programs #0 :List(Program)
}
struct IfProgram {
condition #1 :Program;
trueBody #2 :Program;
falseBody #3 :Program;
}
struct Program {
union {
execute #0 :ExecuteProgram;
sequence #1 :SequenceProgram;
if #2 :IfProgram;
}
}
If I try to compile this the compiler gives the very helpful error message Parse error. I assume it is complaining because I use Program before it is declared.
Is there any way around this?

It turns out you don't need forward declarations, I was just missing a semicolon. What was I saying about Parse error being a terrible error message?

Related

Compare dynamic error message using Error.Is function

I have a dynamic error message for example
metadata.name: invalid value "test-value"
"test-value" will be dynamic, and I need to do something if this error pattern appears
How to check the errors pattern with Error.Is function?
You say your error has a dynamic message. I think you mean that you're defining a type that satisfies the error interface. (If you're using fmt.Errorf instead though, you should define a type for this use case).
type invalidValueError struct {
value string
}
func (e *invalidValidError) Error() string {
return fmt.Sprintf("invalid value %q", e.value)
}
You can check whether any given error has this type using errors.As. This will match not only the error itself, but any errors it's wrapping.
if ive := (*invalidValueError)(nil); errors.As(err, &ive) {
// got an *invalidValueError
}
Avoid matching the text of error messages if at all possible. They can change on different systems or in different locales, and they're generally not covered by compatibility promises.

parse simple terraform file using go

I now tried, everything but cant get this simple thing to work.
I got the following test_file.hcl:
variable "value" {
test = "ok"
}
I want to parse it using the following code:
package hcl
import (
"github.com/hashicorp/hcl/v2/hclsimple"
)
type Config struct {
Variable string `hcl:"test"`
}
func HclToStruct(path string) (*Config, error) {
var config Config
return &config, hclsimple.DecodeFile(path, nil, &config)
But I receive:
test_file.hcl:1,1-1: Missing required argument; The argument "test" is required, but no definition was found., and 1 other diagnostic(s)
I checked with other projects using the same library but I cannot find my mistake .. I just dont know anymore. Can someone guide me into the right direction?
The Go struct type you wrote here doesn't correspond with the shape of the file you want to parse. Notice that the input file has a variable block with a test argument inside it, but the Go type you wrote has only the test argument. For that reason, the HCL parser is expecting to find a file with just the test argument at the top-level, like this:
test = "ok"
To parse this Terraform-like structure with hclsimple will require you to write two struct types: one to represent the top level body containing variable blocks and another to represent the content of each of the blocks. For example:
type Config struct {
Variables []*Variable `hcl:"variable,block"`
}
type Variable struct {
Test *string `hcl:"test"`
}
With that said, I'll note that the Terraform language uses some features of HCL that hclsimple can't support, or at least can't support with direct decoding like this. For example, the type argument inside variable blocks is a special sort of expression called a type constraint which hclsimple doesn't support directly, and so parsing it will require using the lower-level HCL API. (That's what Terraform is doing internally.)
Thanks to #Martin Atkins, I now have the following code that works:
type Config struct {
Variable []Variable `hcl:"variable,block"`
}
type Variable struct {
Value string `hcl:"name,label"`
Test string `hcl:"test"`
}
With that I can parse a variables.tf like:
variable "projectname" {
default = "cicd-template"
}
variable "ansibleuser" {
default = "centos"
}

linter err113: do not define dynamic errors, use wrapped static errors instead

I am using err113 as part of golangci-lint.
It is complaining about ...
foo_test.go:55:61: err113: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"repo gave err\")" (goerr113)
repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, errors.New("repo gave err")),
^
foo_test.go:22:42: err113: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"oops\")" (goerr113)
repoMock.EXPECT().FindAll().Return(nil, errors.New("oops"))
^
What is best way to fix this ?
Quoting https://github.com/Djarvur/go-err113
Also, any call of errors.New() and fmt.Errorf() methods are reported
except the calls used to initialise package-level variables and the
fmt.Errorf() calls wrapping the other errors.
I am trying to get a idiomatic example for this.
Declare a package-level variables as suggested:
var repoGaveErr = errors.New("repo gave err")
func someFunc() {
repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, repoGaveErr)
}
Every call to errors.New allocates a new unique error value. The application creates a single value representing the error by declaring the package-level variable.
There are two motivations for the single value:
The application can compare values for equality to check for a specific error condition.
Reduce memory allocations (although probably not a big deal in practice)
The value io.EOF is a canonical example.
Since GO 1.13 you can define a new error type, wrap it and use it.
for example, if you want to return an "operation not permitted" + the operation.
you need to implement something like
var OperationNotPermit = errors.New("operation not permitted")
func OperationNotFoundError(op string) error {
return fmt.Errorf("OperationNotPermit %w : %s", OperationNotPermit, op)
}
then in your code, when you want to return the error,
return nil, OperationNotFoundError(Op)
Let's back to question case:
first, define the custom error and the wapper
var repoError = errors.New("repositoryError")
func RepositoryError(msg string) error {
return fmt.Errorf("%w: %s", repoError,msg)
}
then in your code,
repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, RepositoryError("YOUR CUSTOM ERROR MESSAGE"))
Since it hasn't been said before, you probably don't need to define package level errors for tests. Given the idea is to wrap errors so they can be compared and unwrapped in the caller, returning a dynamic error in a test is fine as long as the purposes of your test are served.

How to cast a promise error to a custom type?

Hej, I have this piece of code
BsFirebase.Auth.signInWithEmailAndPassword(
Firebase.auth,
~email=self.state.email,
~password=self.state.password,
)
|> Js.Promise.then_(_user => {
// ...
})
|> Js.Promise.catch((error) => {
// ...
})
|> ignore;
In the catch, the error field includes a field code that I can use to have more details about the error.
I'm trying to write a wrapper function to cast the error to a "custom" type but I have no idea how to do it.
So far I have (thanks Jared)
type firebaseError = {"code": int, "message": string}; /* etc. */
external unsafeCeorceToFirebaseError: Js.Promise.error => firebaseError = "%identity";
How can I add extra check to be sure the code property exists in the error ?
One way would be to treat the data structure as JSON, if that's appropriate, and use a JSON decoding library like bs-json since those are designed to deal with unknown or unreliable data structures.
Alternatively, you can type each field as a Js.Nullable.t and test them individually upon use.
Although if you can avoid using promise errors for error handling that would be much preferred, as it's not a type safe way of doing it. Use the result type instead and treat promise errors like exceptions.

Kotlin: "synchronized" makes compiler not to be sure about the initialization of a variable

Let's imagine the next piece of Kotlin code that performs some query to a database by means a JDBC connector:
var results : ResultSet
preparedStatement.clearParameters()
preparedStatement.setInt(1,value1);
preparedStatement.setInt(2,value2)
results = preparedStatement.executeQuery()
while(results.next()) {
// parse results
}
that compiles without problems. However, when I try to add thread safety to the access to the preparedStatement:
var results : ResultSet
synchronized(preparedStatement) {
preparedStatement.clearParameters()
preparedStatement.setInt(1,value1);
preparedStatement.setInt(2,value2)
results = preparedStatement.executeQuery()
}
while(results.next()) {
// parse results
}
... I got a "Variable 'results' must be initialized". It seems the synchronized block acts as a conditional block, but you can be sure that it will be executed once, before the while block.
I have implemented this same block in Java and I don't get the error. Is this a design/implementation error of Kotlin? Or does it have a good reason to behave like that?
synchronized is just an inline function and compiler doesn't know if lambda will be executed once, or even executed at all. Idiomatic way is to return value from lambda and assign it to the local:
val results =
synchronized(preparedStatement) {
preparedStatement.clearParameters()
preparedStatement.setInt(1,value1);
preparedStatement.setInt(2,value2)
preparedStatement.executeQuery()
}

Resources