Wouldn’t parMap :: Strategy b -> (a -> b) -> [a] -> [b] be better fit for this example, instead of using the infix notation?
On a related note: Is it true that future versions of GHC want to make maps and related functions parallel by default? I remember reading about it maybe 1 1/2 years ago, but I don’t think it was an authoritative source?
parMap would achieve the same thing and is probably more idiomatic. I suppose I went with the more verbose version because I wanted to show how the primitives compose into something larger.
The idea of automatic parallelization is interesting. My initial reaction is that just parallelizing everything would probably slow things down due to overhead (starting a spark is cheap but not free). Perhaps you could come up with some heuristics that would work well though.
Are you sure you’re not thinking of data parallel haskell? I don’t see that mentioned in the linked page.
https://wiki.haskell.org/GHC/Data_Parallel_Haskell
Which is mostly abandoned now.
“It would be difficult to reproduce this in a strict language because how could you write a function that produces all natural numbers without looping forever?”
Of course there are multiple ways of doing this in struct languages. The expressiveness of the solution depends on the capabilities of the specific language. Whether it’s better to be strict by default it lazy by default seems to be a matter of preference.
Unless you need to know time or space behavior ahead of time. Example would be real-time segment or supressing covert channels. So far, strict and low-level languages seem to be inherently easier to check for that .
Yes, agreed there are certain situations like these that would lead more to strict evaluation. The general case is closer to a toss up.
I agree it’s possible in a strict language, but I encourage you to keep reading the article. Java has Iterator, Scala has Stream, Python has generators, etc. The point I make in the article is that approximating a lazy list with an Iterator (or Stream, or generator) is less natural and incurs its own complexities.
I disagree with the statement I originally quoted, above. I don’t believe anything in the article justifies that claim. As I wrote, in some strict languages the expressiveness may be cumbersome. But that is due to the specifics of those languages, not due to strict evaluation per se.
For example any language with a reasonable macro capability is going to accommodate explicit lazy evaluation pretty well. See for example…
Thanks Keith! I’ll take a look at what my options are. My main concern is that those buttons are often used for tracking. On the other hand, people who care about that are probably already using things like ad blockers anyway.
I like that you care about tracking :) I don’t think users will mind though, most websitez do track users. I use “sharethis” it’s free but, yeah, They track users as much as Google does.
:)) Well, the process for both:
Share button = click.
No share button = Ctrl+d, Ctrl+c, Ctrl+t, [start typing twitter until it is auto-suggested by browser address bar], scroll to the suggested, ENTER, Wait for loading, Click the tweet button, Ctrl+v, click tweet again.
The 1st option kind of encourages you to share and the user stays in same window or web page.
I’m not saying that they’re equally easy. But even #2 only takes a couple of extra seconds. I bet it took you longer to type that response ;-p
Does this mean that ultimately, many of us will be bitter about how lousy Go is, and wish for something better? That’s a bummer, Go is really quite nice. But it’s awesome because eventually, there will be something so fabulous it makes Go look like garbage. :D
Also regarding Go and generics, I see the usefulness/complexity thing cited everywhere, but how does Go as a language help avoid needing generics? Slices, maps, and channels are generic, is that really all you need to do things?
But it’s awesome because eventually, there will be something so fabulous it makes Go look like garbage. :D
I’ve already seen many things which make it look like that.
Slices, maps, and channels are generic, is that really all you need to do things?
No, and so Go requires you to lie to the type system (i.e. cast) when you want to do things generically.
You can’t just throw Go under the bus saying it “looks like garbage” without naming the languages you feel are superior.
The above are much more capable of writing reusable functions. Some are again much more capable than the others, but the bar is pretty low!
Whining about a language is a waste of everyone’s time. If you have something useful to contribute, do so. Plenty of people have given detailed, reasoned, substantial accounts of their experiences with Go, good and bad. Maybe it wasn’t clear, but that sort of answer is the kind I was inviting.
Criticising things is an important thing to do.
I’d argue that constructively criticizing things is an important thing to do. If criticism isn’t constructive, then you have little hope of the right people reconsidering what they think they know.
Your comments in this thread are certainly not constructive.
Taking this discussion meta, how would you classify your comments as not smug? I agree that criticism is important, but I don’t see how you have done anything but call Go garbage and list languages with generics of some variety.
Criticizing things is indeed an important thing to do, but you haven’t succeeded in doing it so far.
No, and so Go requires you to lie to the type system (i.e. cast) when you want to do things generically.
Go supports a different form of compile time safe polymorphism via structural sub-typing. No lying necessary.
I agree that Go supports a single, limited form of polymorphism. Very quickly you come to a point where you have to lie.
In what situations? When you are writing your own generic containers you run into a problem, but otherwise when you you actually need more than an interface? The built in containers are quite capable for most applications. If you truly need a specific data structure, how often are you going to need to use it on any possible type? A database may use a skip list for good concurrency working with tuples. A text editor may use a rope for working with strings. I would argue that using those specialized data structures generically in every situation is marginally useful.
The Go developers argue that generics are not adequately useful to be added, and I haven’t seen a compelling example that indicates otherwise, do you have one?
The built in containers are quite capable for most applications. If you truly need a specific data structure, how often are you going to need to use it on any possible type?
I want a Tree data structure, maybe I’ll only use it on 3 different types of values in my application but why:
The 3rd point might not seem like a problem but it has huge implications, documented in a concept called parametricity.
I would argue that using those specialized data structures generically in every situation is marginally useful.
It’s not just data structures. Functions shouldn’t have to be unnecessarily specialised. If I need to write a function like so:
func idInt(a int) int {
return a
}
Why should we care about whether it’s an int or a string or a gobbledok? Our alternative is to use an interface:
func id(a interface {}) interface {} {
return a
}
But now we know nothing about the output type when we go to use it. We’d have to cast - will that work? Only after knowing exactly the definition of the function do we know for sure.
I hope I don’t have high standards by refusing to use a system which doesn’t allow using types as documentation or which asks for information it doesn’t need nor use.
I am familiar with all of the concepts you described. However, Go emphasizes simplicity. I haven’t ever heard someone claim that they encountered a serious problem with lack of total parametric polymorphism that so critically impeded their ability to write their application that they would trade away the simplicity of Go. Go was designed for a specific purpose, to write concurrent applications that are easy to reason about, both in terms of their concurrent aspects and performance as a whole.
It’s not just data structures. Functions shouldn’t have to be unnecessarily specialised.
This is really more of a philosophical point than a practical one. While such a feature is nifty, it’s not that useful. We can talk all day about how neat monads are (really neat), or how map is so more elegant than a for loop, but at the end of the day when you are writing an network server chewing through tens of thousands of requests per second, reasoning about the exact performance characteristics of a for loop is easier.
I want a Tree data structure
Why? Why not use a map? There are plenty of ways to use trees besides maps, ways that involve custom, non-generic logic to create and maintain the tree to reap some performance benefit or other desirable characteristic.
I hope I don’t have high standards by refusing to use a system which doesn’t allow using types as documentation or which asks for information it doesn’t need nor use.
You have different priorities. You aren’t wrong for your priorities, and your priorities don’t make all other priority sets wrong. You seem to be claiming that the lack of generics is so crippling that Go is trash not worth using, by anybody. That’s how I read your tone anyway. But that flies in the face of reality: plenty of people are accomplishing significant feats with Go, without generics. I originally asked what language features—or possibly characteristics of the problems Go is solving—accommodate the lack of generics. Why do the developers feel they aren’t useful enough to add? Defending Go has made me come up with concrete reasons, and I have answered my question for myself.
Very quickly you come to a point where you have to lie.
I don’t think so. Go is about making the simple decision, not the ultra nifty yet often unnecessarily complex one. Make the simple choice, and you don’t have to lie. That puts Go at the opposite end of the spectrum from languages like Haskell, a trait that a lot of people consider a feature.
Also, I should note that around 4 years ago I too thought Go was a sensible idea and I was using it for things but I noticed the problems and started using more capable tools.
This is really more of a philosophical point than a practical one.
No, code duplication is a very practical issue - it’s ridiculous to say otherwise.
.. reasoning about the exact performance characteristics of a for loop is easier.
Parametric polymorphism is not about for loops.
Why? Why not use a map?
Do you see the irony here? Making a false compromise in the name of performance but then sacrificing it by using a Map?
You seem to be claiming that the lack of generics is so crippling that Go is trash not worth using, by anybody.
Yes, I refuse to use a language which doesn’t allow code reuse and I’ll point out the silly false sacrifice made for “simplicity” reasons. I think more should have the same standards.
That’s how I read your tone anyway
I have no tone.
But that flies in the face of reality: plenty of people are accomplishing significant feats with Go, without generics.
People are accomplishing things despite the lack of generics, by not abstracting and not reusing code.
Why do the developers feel they aren’t useful enough to add? Defending Go has made me come up with concrete reasons, and I have answered my question for myself.
I have seen the answer, too. They put up with code duplication and don’t allow abstraction.
Go is about making the simple decision, not the ultra nifty yet often unnecessarily complex one.
Parametric polymorphism as a type system feature has been around for about 30 years now. It’s extremely simple to describe and implement.
Go’s “simplicity” (i.e. lack of parametric polymorphism) is a silly thing to trade for. Your application becomes more complicated because of no abstraction and no code reuse so that the language spec doesn’t spend a few paragraphs defining parametric types!
I just searched Twitter for #golang to see what other strange things were being said and I immediately saw this monster:
https://clipperhouse.github.io/gen/
The solution for lack of generics? A code generation tool!
https://github.com/clipperhouse/gen/blob/master/templates/projection/projection.go
This is simplicity?
C++ templates are just fancy code generation. Well, fancy is a stretch. Built in though.
Having a type system that handles generics is a better solution for generics, certainly. But code generation isn’t horrific in of itself. It’s one of many tools in the world of programming tools, and is fairly easy to work with. Protobufs use code generation to make parsers and interfaces, and that’s fine in my opinion.
I read: generics aren’t necessary, code generation rather than generics is fine.
Very strange ideas!
For certain kinds of applications, sure. Because for certain applications generics aren’t that important.
I can’t think of any nontrivial applications for which generics wouldn’t be useful. Besides code reuse, parametric polymorphism gives you better reasoning about what your code is doing via parametricity/free theorems.
Now, I’m not saying that generics won’t be somewhat useful for a lot of these. Of course they would in some parts of code. But most of those use cases are covered with Go’s typing system. The amount of times you need to be able to specialize some code to literally any type ever is not that high. An interface will do just fine.
Yes, I refuse to use a language which doesn’t allow code reuse
They put up with code duplication and don’t allow abstraction.
Seriously?
Parametric polymorphism as a type system feature has been around for about 30 years now. It’s extremely simple to describe and implement.
Then why are C++ templates are such a mess? And why is it that Java generics are implemented with type erasure, don’t work with primitives, and aren’t safe with arrays?
You are right though, it’s even said on the Go site that some code duplication is the preferred solution to certain things. Many people find that a small amount of duplicate code is acceptable in certain circumstances, otherwise the industry standard would be Haskell. For an application that necessarily relies heavily on generic types, I wouldn’t pick Go.
Your application becomes more complicated because of no abstraction and no code reuse so that the language spec doesn’t spend a few paragraphs defining parametric types!
Exactly zero abstraction is ideal. Main is the only function anyone needs.
Then why are C++ templates are such a mess? And why is it that Java generics are implemented with type erasure, don’t work with primitives, and aren’t safe with arrays?
Exactly zero abstraction is ideal. Main is the only function anyone needs.
I truly hope and believe this is not a position shared by many!
A big part of the reason why generics are such a mess is because of the intersection of subtyping and parametric polymorphism. IMO, get rid of subtyping and use row polymorphism for records.
The point is, generics are actually pretty hard and complicated, even for people who understand them.
I truly hope and believe this is not a position shared by many!
CS 101 students around the world are pioneering this strategy!
Your examples only show that retrofitting or piggy-backing on features to get parametric polymorphism has always resulted in sadness. Implementing generics as a goal is extremely simple - I’ve done it many times!
Also, from what I’ve heard from developers on the Rust team, making everything work just right is actually extremely challenging for them. The common complaint I hear is that the type system touches everything, so working with it is difficult.
Nice, well written. Although everyone in my college Programming Languages class wrote a type annotator for a similarly trivial “language” during lab one day in about an hour. A real programming language is quite a bit harder.
He listed earlier many “real programming languages” with parametric polymorphism. It’s not exactly a colony on Mars. This is something we’ve known how to do for literally decades. And saying that languages shouldn’t have parametric polymorphism because you personally think it’s difficult to implement is like saying cars shouldn’t have transmissions or 4-stroke engines for the same reason.
Not being able to write generic data structures in Go without casts is awful and basically inexcusable for a modern language that wants to be taken seriously.
He listed earlier many “real programming languages” with parametric polymorphism.
Which one has a perfect system? The Go developers won’t introduce one because they can’t see a clean way to do it that jives with the rest of the language.
And saying that languages shouldn’t have parametric polymorphism because you personally think it’s difficult to implement is like saying cars shouldn’t have transmissions or 4-stroke engines for the same reason.
Because it’s difficult to get right, for a lot of people, including the very capable people on the Go team. Side note, Tesla is doing well.
Not being able to write generic data structures in Go without casts is awful and basically inexcusable for a modern language that wants to be taken seriously.
I mean, it kinda sucks. I’ve never been that bothered. A lot of companies are writing critical infrastructure in Go, and the word critical implies they are taking it seriously. Writing correct, fast, and maintainable Go code is easy, and a lot of people like that.
There are no casts in Go. You can convert primitive types (such as string to []byte or int to float64), but when working with interface{}, you can’t convert, you can only do type assertions. Type assertions will fail if the asserted type doesn’t match, so you still have type safety at runtime. You still can’t hammer a square piece through a round hole.
so you still have type safety at runtime
There is no such thing as runtime type safety. Go’s “type assertions” are in every way a type cast.
T must implement the (interface) type of x; otherwise the type assertion is invalid since it is not possible for x to store a value of type T. If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.
If the type assertion holds, the value of the expression is the value stored in x and its type is T. If the type assertion is false, a run-time panic occurs. In other words, even though the dynamic type of x is known only at run time, the type of x.(T) is known to be T in a correct program.
(Emphasis mine.)
So I’m afraid you are mistaken: type assertions are not at all like a type cast – at least not like a type cast in a weakly typed language like C, wherein they instruct the compiler to treat x as being of type T regardless of what its actual type at runtime is.
Now type assertions in Go do allow you to compile code that is not always correct, including code that is never correct. Nevertheless, they do not allow you to run code that is not correct, and thus are safe, much unlike type casts in a language like C.
Just because you can write this in Java:
if(x instanceof String) {
println((String)x);
}
And it won’t crash, doesn’t mean you’re not casting.
I was responding to your claim that a) there is no such thing as runtime type safety and b) type assertions in Go are therefore not safe.
Now in what way is your Java code example unsafe? Will it ever run incorrect code? Not as far as I can tell.
It is clear that Java’s casting does allow you to compile incorrect code, like Go’s type assertions do. I’ve already said so. (Though arguably the code in your example is not even ever incorrect.)
So if you were trying to make a point about my reply, I can’t see what that is.
There is not such thing as runtime type safety.
Yes there is. Compare the result of running python -c '"1" + 1' and php -r '"1" + 1;'. The difference is a result of Python having more type safety than PHP, which is checked at runtime.
This is a form of safety, but it’s not static type safety. From Types and Programming Languages:
Refining this intuition a little, we could say that a safe language is one that protects its own abstractions. Every high-level language provides abstractions of machine services. Safety refers to the language’s ability to guarantee the integrity of these abstractions and of higher-level abstractions introduced by the programmer using the definitional facilities of the language. For example, a language may provide arrays, with access and update operations, as an abstraction of the underlying memory. A programmer using this language then expects that an array can be changed only by using the update operation on it explicitly—and not, for example, by writing past the end of some other data structure. [1]
So Go will let you know at runtime if you’re casting between two incompatible types, and this is a form of safety, but not static type safety. Similarly, Python won’t let you index past the end of a list, and this is a form of safety, but, once again, not type safety.
Pierce continues:
Language safety is not the same thing as static type safety. Language safety can be achieved by static checking, but also by run-time checks that trap nonsensical operations just at the moment when they are attempted and stop the program or raise an exception. For example, Scheme is a safe language, even though it has no static type system. [2]
In the end, this is mainly an argument about definitions, but it’s important to get these definitions right when discussing language design tradeoffs, especially when these definitions clue us in to real differences between languages.
For what it’s worth, I think Go’s lack of parametric polymorphism is absolutely crippling.
[1] Pierce, Benjamin C. (2002-02-01). Types and Programming Languages (Page 28). MIT Press. Kindle Edition.
[2] Ibid.
So Go will let you know at runtime if you’re casting between two incompatible types, and this is a form of safety, but not static type safety.
I don’t understand why you’re saying this. I’m not talking about static type safety. I’m talking about type safety at runtime. Puffnfresh has claimed that no such thing exists. I’ve provided a counter-example.
This is basically a conclusion drawn from the distinction made between strongly and weakly typed languages. It’s not like I’m pulling this out of thin air.
For what it’s worth, I think Go’s lack of parametric polymorphism is absolutely crippling.
For what it’s worth, I disagree.
Both PHP and Python only have a single type, so it’s kind nonsensical to claim that one has more type safety than the other at least using a TaPL definition of the word “type”. What they do have is different runtime semantics for handling values with different runtime tags, which colloquially these languages unfortunately refer to as “types”.
I cannot see any point you’re making other than to indulge in a definition war. If we were at ICFP and I started talking about the type safety of Haskell and Python as if they were the same thing, then I’d applaud your correction. But in a wider audience, it’s quite clear that comparing the type safety of languages like Python and PHP is a perfectly valid and natural thing to do.
It’s not a word game, my point is that I question whether this alternative definition of the term actually gives rise to a well-defined comparison or ordering at all. What could it possibly mean for a programming language to “go wrong less” than another programming language if they both admit an infinite number of invalid programs? Hypothetically If I have a language Blub can I always form a language Blub' that is less type safe than Blub and what would I have to alter to make it so? This kind of redefinition just leads to nonsense.
This kind of redefinition just leads to nonsense.
My example up-thread contrasting Python and PHP is absolutely not nonsense. The distinction between them is a result of a difference in each language’s type safety.
I mean, hell, if you try running the Python code, you’ll get an exception raised aptly named TypeError. What other evidence could possibly convince you?
My example up-thread contrasting Python and PHP is absolutely not nonsense.
It is a nonsensical notion if you take it to it’s logical conclusion, that there exists this alternative notion of “type safety” in terms of their runtime semantics that we can compare languages based on. Sure, you can contrast the addition function for a fixed set of arguments, but how do you generalize that to then make a universal claim like “Python has more type safety than PHP”.
If it’s a well-defined concept, then suppose I gave you [Python, Fortran, Visual Basic, Coq, PHP] what would be the decision procedure in the comparison “function” used to order these languages for your notion of type-safety?
It is a nonsensical notion if you take it to it’s logical conclusion
Why do I have to take it to its logical conclusion? The distinction exists today. Python is strongly typed and PHP is weakly typed. These descriptions are commonly used and describe each language’s type system.
Sure, you can contrast the addition function for a fixed set of arguments
The addition function? Really? That’s what you got out of my example?
Try this in a Python interpreter:
def x(): pass
x(0)
What do you get? A TypeError!
If it’s a well-defined concept
Who says it has to be well defined? I certainly didn’t. I’m merely drawing on the established conventions used to describe properties of programming languages.
I still truthfully don’t understand what your central point is. Are you merely trying to state that there exists some definition of type safety for which it is nonsensical to ascribe to dynamically typed languages like Python or PHP? Great. I never contested that. But that does mean you’re just playing word games, because it’s patently obvious that that definition isn’t being invoked when discussing type safety of precisely the languages that your definition of type safety doesn’t apply to.
There is no such thing as strong or weak typing for the same reason there is no such thing as runtime type safety. They’re not well-defined.
OK. So you’re playing word games. Just as I thought.
Concepts such as strong and weak typing exist and they are used to draw meaningful comparisons between languages all the time. So you covering your ears and simply saying this doesn’t exist is a bit ludicrous.
They can’t and shouldn’t be used to draw conclusions about programming languages at all unless they have a precise meaning, which they don’t. The fact that they are used all the time to make specious arguments doesn’t make them any more accurate or precise, that’s just a consensus fallacy.
They can’t and shouldn’t be used to draw conclusions about programming languages
Except they are. I’ve given examples to support my claim. You’ve done nothing but appeal to your own definition.
I’ve committed no fallacy because I’ve drawn no conclusions from the fact that there is a consensus. I’ve merely pointed out that there exists a consensus. (Which you absurdly claimed doesn’t exist!)
I’ve merely pointed out that there exists a consensus.
No really, there isn’t a consensus on these terms. Even the Wikipedia article on the terms “weak and strong typing” prefixes everything it says by saying they have no precise meaning and that many of the proposed definitions are mutually contradictory, and should be avoided in favor of more precise terms. Probably this answer is the best explanation of why the terms are themselves completely meaningles, they’re just used for sophistic arguments to justify preconceived bias about language features.
Which is why I claim the defining this new term “runtime type safety” in terms of these other ill-defined terms is fallacious.
It boggles my mind that you think I’m trying to precisely define anything. I’m not. I’ve merely pointed to the facts: the terms weak typing and strong typing have meaning, and are used to compare and contrast language features in a way that effectively communicates key differences. These differences relate to the way types are handled at runtime.
I never once said that there weren’t any problems with these terms or that they weren’t vague.
Welcome to the subtleties of human language. You’re arguing about what should be. I’m pointing out what is.
you still have type safety at runtime
There are two kinds of type safety: Static types and strong types.
What you are describing is strong types; safety at run-time. Static types go beyond that; they give safety at compile-time.
Now, in Java, generics are implemented with static type guarantee. But there is a catch; the type parameters are erased after compilation. Also, Java doesn’t support co-variant types, which means, you end up type-casting / type-asserting sometimes, though it is not very often.
However, if a language doesn’t support generics at all, then you have to use type-casts / type-assertions every time you need to reuse code!
However, if a language doesn’t support generics at all, then you have to use type-casts / type-assertions every time you need to reuse code!
And that language isn’t Go.
I swear, this whole thing is messed up. Gophers tend to overstate the power of structural subtyping and people who haven’t written a lick of Go seem to dismiss it entirely. Believe it or not, Go actually does have a mechanism for compile time safe polymorphism. And yes, that means static types!
The quoted sentence of mine was deliberately brief. There are many ways for a language to facilitate code reuse. Structural sub-typing allows code reuse in a different way than generics. You can’t create type-safe and re-usable collections with structural sub-typing for example.
I never implied otherwise. I made the comment I did because there are others in this thread that are repeatedly stating inaccuracies about Go. Namely, that it has no mechanisms for code reuse. Given that context, it’s unclear exactly what you were implying.
And that brings me back to my point. People seem to think that just because Go doesn’t have their favorite blend of polymorphism that Go has none of it at all. Or at the very least, completely dismiss structural subtyping simply because it’s different from what you like.
As far as code reuse goes, structural subtyping is only one piece of the puzzle. Go also has type embedding and properly implemented first class functions. (Which sounds like a weird benefit to quote, but not every language gets lexical scoping exactly right. Go does.)
The password generator script in the post uses random.choice which is not a cryptographically secure source of entropy. From the python docs [1]:
The Mersenne Twister is one of the most extensively tested random number generators in existence. However, being completely deterministic, it is not suitable for all purposes, and is completely unsuitable for cryptographic purposes.
That’s a bit confusing as the issue isn’t that it’s deterministic. It’s that given enough output, you can predict future output.
This attack might not be feasible against a 4 word long password, but why risk it when there are alternatives? random.SystemRandom is probably cryptographically secure, but doesn’t explicitly say it in the docs [2]. My own password generator [3] uses PyCrypto’s CSPRNG [4].
[1] https://docs.python.org/2/library/random.html
[2] https://docs.python.org/2/library/random.html#random.SystemRandom
[3] https://github.com/beala/xkcd-password
[4] https://www.dlitz.net/software/pycrypto/api/current/Crypto.Random.random-module.html
random.SystemRandomis probably cryptographically secure, but doesn’t explicitly say it in the docs [2].
It actually does. SystemRandom defers to os.urandom, which per its own docs
…should be unpredictable enough for cryptographic applications, though its exact quality depends on the OS implementation.
There is an important lesson to be learned here about coding standards. This particular bug would have been obvious if either:
gotos were forbidden, in which case this could would have been a series of else if blocksif requires {} even if they are only one statement.IMO, all-out banning goto is too extreme, but enforcing the second one is a good idea and it an be automated as part of a test framework.
Personally, I’m very against optional syntax, saving a few lines of code is not worth this bug.
Personally, I’m very against optional syntax, saving a few lines of code is not worth this bug.
Agreed. Fancy character-saving syntax tricks are about ego and programmer pissing matches. I say: Save that stuff for the obfuscated code contest. If you want to work for me or with me, then your cleverness had better be directed towards furthering our mutual goals. Code should be written for easy readability, not for showing off your knowledge of the ins and outs of the language.
[Comment removed by author]
I’m less concerned with Apples coding standards than I am by the fact they don’t appear to have a single negative unit test to check that a wrong cert is detected.
From the original article:
A test case could have caught this, but it’s difficult because it’s so deep into the handshake. One needs to write a completely separate TLS stack, with lots of options for sending invalid handshakes. In Chromium we have a patched version of TLSLite to do this sort of thing but I cannot recall that we have a test case for exactly this. (Sounds like I know what my Monday morning involves if not.)
I spent a while as an embedded engineer, where we made heavy use of goto and braceless ifs, particularly for the construct
if (condition_a)
if (condition_b)
if (condition_c)
if (condition_d)
...
do_something();
as opposed to long if (condition_a) && (condition_b) ... statements.
I don’t really see the benefit there. It’s not like the number of symbols in the source means much for the compiled code.
The official Tor blog has a post on this further clarifying how this data should be interpreted: https://blog.torproject.org/blog/what-spoiled-onions-paper-means-tor-users
I would actually suggest that you don’t accept PRs, and instead only add ones that you’ve personally vetted. If there is no acceptance criteria, except that it’s related to tech and someone somewhere suggested it, this becomes more of a directory and less of a “must listen” list. Both are valuable, but from the description, it sounds like you’re trying to build the latter.