3 ms·
Yes exactly. Although I think with Generics they will probably come around at some point. If you read the link I posted they do recognized there are unsolved ca
by jeremyjh 14y ago
Yes exactly. Although I think with Generics they will probably come around at some point. If you read the link I posted they do recognized there are unsolved cases without Generics and while some people DO say "just rewrite your collections over and over when you can't use maps/slices", others recognize that this will lead to redundant code which is not something you want in a language touted for its maintainability.
Other problems though such as default function parameters are less likely to be addressed (it seems to me). This is a problem because it means lots of code will be written in which there are implicit defaults (just pass 0!) that are not well-understood or guaranteed by the interface. The answer there is "just write another method with a different name and parameters". Ok so now I have to think of sensible names for the methods that are exactly the same as another method except they apply defaults...and write and maintain more code of course - especially if its in an interface you re-use.
- EdiX 14y ago> Other problems though such as default function parameters are less likely to be addressed (it seems to me). It's unlikely to be addressed given that Google style guide forbids using default function parameters even in C++. > This is a problem because it means lots of code will be written in which there are implicit defaults (just pass 0!) "Just pass 0" is not a good way to implement defaults.
- dchest 14y agoToday I was writing a Skein hash function implementation in Go. Skein can be configured for different purposes (e.g. MAC, KDF, stream cipher, etc.), and it can accept >5 optional arguments. I wanted to expose all these configuration option to users, in addition to providing a simple version that will create hash without configuration. Here's how I solved it (there's prior art in some standard libraries). I exported this struct: type Args struct { Key []byte // secret key for MAC, KDF, or stream cipher Person []byte // personalization string PublicKey []byte // public key for signature hashing KeyId []byte // key identifier for KDF Nonce []byte // nonce for stream cipher or randomized hashing } and then provided a function: func New(outLen uint64, args *Args) *Hash Users can easily call it like this: h := skein.New(64, &skein.Args{ Key: someKey, Nonce : someNonce }) I like this design a lot. Plus, with structs as arguments you can easily provide more than one default configurations. For example, if you want to personalize hash for different usages: var FileHashConfig = &skein.Args{ Person: []byte("file hash for MyApp") } var MessageHashConfig = &skein.Args{ Person: []byte("message hash for MyApp sync") } and use them: h := skein.New(64, FileHashConfig) (Note: Args is a bad name for general usage -- I called it like this only because Skein authors call these "arguments", and "configuration" is reserved for something else.) There are a few specified usages for Skein with arguments, so to avoid making users of my library read the Skein paper, I wrote "constructors" for them: // NewMAC returns hash.Hash calculating Skein Message Authentication Code of the // given length in bytes. A MAC is a cryptographic hash that uses a key to // authenticate a message. The receiver verifies the hash by recomputing it // using the same key. func NewMAC(outLen uint64, key []byte) hash.Hash { return hash.Hash(New(outLen, &Args{Key: key})) } // NewStream returns a cipher.Stream for encrypting a message with the given key // and nonce. The same key-nonce combination must not be used to encrypt more // than one message. There are no limits on the length of key or nonce. func NewStream(key []byte, nonce []byte) cipher.Stream { const streamOutLen = (1<<64 - 1) / 8 // 2^64 - 1 bits h := New(streamOutLen, &Args{Key: key, Nonce: nonce}) return newOutputReader(h) } Simple.
- jeremyjh 14y agoSo depending on the algorithm you are using, you are going to leave some of these fields in the struct as null/empty? To me this is the whole issue. Of course if we have knowledge outside the method declaration about what values can be left 0, then we can pass the correct ones as needed. But the interface is ambiguous about when that is acceptable, and the implementation can change without changing the interface. According to the mail lists I've read on the subject, the correct way to implement your algorithms in Go would be for each to be a separate method. And indeed that is the only way in Go to support a fully specified interface.