golang code organization: where should I put custom error types that are only relevant to one function? - go

I have just started working on my first golang project and really like the idea of returning custom error types from functions and using type assertion in the calling code, to check for specific errors. I find this solution cleaner than always comparing error messages.
My only question is: where do you best put these custom error types?
Say a number of custom error types is only used (returned) by one utility function, should they go in the same package as the function? Should I group them somehow? Or maybe there's a better way of doing this kind of thing..

"Same package" would be my initial thought. There may be cases where having them in a different package would make sense, but that would only be if they're legitimately "the same error" from functions in multiple packages, with none of those packages being the logical "most owner".

Related

Using unexported functions/types from stdlib in Go

Disclaimer: yes I know that this is not "supposed to be done" and "use interface composition and delegation" and "the authors of the language know better". However, I am confronted with a choice of either copy-pasting from the standard library and creating my own packages, or doing what I am asking. So please do not reply with "What you want to do is wrong, you are a bad dev and you should feel bad."
So, in Go we have the http stdlib package. This package has a number of functions for dealing with HTTP Range headers and responses (parsers, a struct for "offset+size" and so forth). For various reasons I want to use something that is very similar to ServeContent but works a bit differently (long story short - the amount of plumbing needed to do the ReaderAt gymnastics is suboptimal for what I want to accomplish) so I want to parse the HTTP Range header myself, using the utility functions/structs from the http stdlib package and then deal with them manually. Basically, I want a changed version of ServeContent :-)
Is there a way for me to "reopen" the http stdlib package to use it's unexported identifiers? ABI is not a concern for me as the source is mine, the program gets compiled from scratch every time etc. etc. and it does not need binary compatibility with older/other Go versions. I.e. I am able to ensure that the build is going to be done on a specific Go version and there are tests to check that an unexported identifier disappeared. So...
If there is a package called foo in the Go standard library, but it only exposes a MagicMegamethod that does the thing I do not need, and uses usefulFunc and usefulStruct that I want to get access to, is there a way for me to get access to those identifiers? Either by reopening the package, or using some other way... that does not involve copy-pasting dozens of lines from stdlib without tests etc.
There exist (rather gruesome) ways of accessing unexported symbols, but it requires nontrivial amounts of tricky code, so there's unlikely to be a net win.
Since you've outruled the "don't do this" direction, it seems that the answer is either NO or use the methods described in the post I linked to (and this repo).
FWIW I'd personally just copy the code I need from the standard library and tweak it to my needs. This would likely take less time than the time it took you to write this SO question :-)

Autoloading Hack type aliases

Is there any way autoload Hack type aliases? I've placed them in separate files on PSR-4-compliant paths, and although I understand they are Hack-only and aren't formally mentioned in the PSR-0 or PSR-4, I figured one of the following would happen:
HHVM would expand type aliases to their base types, or
spl_autoload would treat the type as a class, function or interface name and execute the script, resolving the alias.
However, neither happen. At runtime, the methods call fail due to incompatibility with the type hints, i.e.:
Catchable fatal error: Argument passed to {method_name} must be an instance of {type_alias}, {concrete_type} given.
Edit: I should mention that I am specifically using Composer. I'm unsure if this is Composer-specific or not.
Yes, you can autoload types in HHVM. You need to be using a class-map approach and the HH\autoload_set_paths function.
There is the hhvm-autoload package which adds support for generating the necessary map into composer.
I don't believe this is possible. PHP doesn't register type hints for autoloading. And it doesn't need to, because the only way to fulfill the type hint is to pass that class or subclasses, whose construction would've triggered the autoloader call. It is impossible then for a type hint to be unknown to the interpreter at the time it checks against it.
This is only a problem in Hack because type aliases introduce this possibility. To stay consistent with PHP, I expect the only viable solution of the two mentioned would be for HHVM to expand type aliases while compiling the bytecode.

Create constants visible across packages, accessible directly

I would like to define my Error Codes in a package models.
error.go
package models
const{
EOK = iota
EFAILED
}
How can I use them in another package without referring to them as models.EOK. I would like to use directly as EOK, since these codes would be common across all packages.
Is it the right way to do it? Any better alternatives?
To answer you core question
You can use the dot import syntax to import the exported symbols from another package directly into your package's namespace (godoc):
import . "models"
This way you could directly refer to the EOK constant without prefixing it with models.
However I'd strongly advice against doing so, as it generates rather unreadable code. see below
General/style advice
Don't use unprefixed export path like models. This is considered bad style as it will easily globber. Even for small projects, that are used only internally, use something like myname/models. see goblog
Regarding your question about error generation, there are functions for generating error values, e.g. errors.New (godoc) and fmt.Errorf (godoc).
For a general introduction on go and error handling see goblog
W.r.t. the initial question, use a compact package name, for example err.
Choosing an approach to propagating errors, and generating error messages depends on the scale and complexity of the application. The error style you show, using an int, and then a function to decode it, is quite C-ish.
That style was partly caused by:
the lack of multiple value returns (unlike Go),
the need to use a simple type (to be easily propagated), and
that gets translated to text with a function (unlike Go's error interface), so that the local language strings can be changed.
For small apps with simple errors strings. I put the packages' error strings at the head of a package file, and just return them, maybe using errors.New(...), or fmt.Errorf if the string needs to be completed using some data.
That 'int' style of error reporting doesn't offer something as flexible as Go's error interface. The error interface lets us build information-rich error structures, to return useful information, and not just an int value or string.
An implication is different packages can yield different real-types which implement the Error interface. We don't need to agree a single error real-type across an entire set of packages. So error is an interface which can be easily propagated, like an int, yet, the real-type of error can be much richer than an int. Error generation (implementing Error) can be as centralised or distributed as we need, unlike strerror()-style functions which can be awkward to extend.

Pipelines with error handling in Clojure

I'm looking for a smart way to create composable validation and transformation pipelines in Clojure. The aim is to be able to do simple translation and validation of messages using composable steps.
Main requirements:
Can be composed functionally, i.e. pipelines are pure functions
Can be applied to regular Clojure data types (maps, vectors, lists, and nested combinations thereof)
Can perform transformations, e.g. renaming a key in map
Can perform arbitrary validations (e.g. applying a Schema validation to part of a message)
Can bail out gracefully when errors are detected, and return a meaningful error message (not just throwing an exception!)
I guess I can write all this, but don't particularly feel like reinventing the wheel today :-)
Dopes anyone know of a tool that can do this, or have a good idea regarding how to construct one in a clever and general way?
You might look at Zach Tellman's Lamina library. You can create pipelines of functions with error handlers as other useful functionality.
You might find Promenade (see documentation), a library I have been working on for elegant error handling and control flow, useful for some of the things described in the question.

llvm: is it possible to merge validation and compilation in a single stage?

Generally speaking, when writing a llvm frontend, one will take an AST and first check that its semantics is well-defined. After this, one will take the AST and perform the IR build phase.
I was wondering, how realistic is to perform directly the IR build phase onto the AST, and if errors are found during the build process, revert any partial changes to the module object?
I assume something like this would be required:
remove defined Types
remove defined Globals
anything else i'm missing?
Any ideas about this? what are the general guidelines of what needs to done for a clean revert of module changes after a failed build phase?
Now, this is thinking in terms of optimistically compiling, and failing gracefully it somethings goes wrong. It might very well be that this is completely impossible or discouraged under the current LLVM model. A clear and well-documented answer in this regard is also completely acceptable
Edit In the end, I just want a reasonable way to add functions incrementally but revert gracefully to previous state of module and/or LLVMContext if a function build fails. Whatever is the preferred approach for that will be entirely satisfactory.
thanks!
Many compilers (not necessarily LLVM-related) mix semantic analysis with code generation, so it can definitely be done. However, I'm puzzled by your reference to "revert any partial changes to the module object". When you start building an IR module and encounter a semantic error in the AST, what is your plan? Do you want to spit an incomplete module? Why? Thinking about the way any regular compiler works, if there are semantic errors in the code (i.e. reference to an undefined variable), no output is created. Would you like something different?

Resources