Very very cool. I love their approach of looking for similarity metrics that are less sensitive to local misalignment, and this is something I'me very interested in exploring in the future.
I'm not completely convinced by their distinction between "tone-based" and "structure-based", though. When they talk about structure, it seems to primarily mean 'edges'. Instead maybe a more useful distinction would be between "local optimization" (at the level of a single printed character), and optimizing "globally" or over a wider area of the image, and so allowing an iterative optimizer to find a really compact representation.
Yes, it is sad. OpenCV has a code-gen for Java/Python but they are hard to work with. A number of projects in other programming languages (Rust [1], Go [2]) has to use custom build wrappers.
And the links from there are a pretty good start. Start with just basic asset tracking (checking, savings) and liability tracking (debt, CC) and get into the routine of it. Then you can add in your investments and other assets (car, home, stocks, foreign currency holdings, etc.). If you don't care about a slightly inaccurate history, just add the stocks later on at their present value, or go back and find your initial purchase dates and cost basis and let ledger calculate your present gain/loss.
It's a language that let you start small, and progress a lot with the complexity of your code. You can be productive in Python in 3 days if you know another language. But you can still learn new Python useful things 10 years after you started.
The progress curve is very sane.
And in the same way, your project may start small, then you add docstrings, classes, modules, packaging, unittests, infrastructure... And at some point, you may want types.
I use types on maybe 10% of my code in Python. It's great it's not mandatory. And it's great it's here when I benefit from it.
I write Python in my day job and I _always_ start with types. I find they make even prototype code so much easier to reason about. It's just nice to be able to tell at a glance what a function returns, what args it takes, etc., and I don't have to master Sphinx's cryptic syntax (which I still haven't managed after using it for 5 years). And I experience this benefit even for code that I wrote yesterday without even running the type checker. And it's only going to get better with editor integration.
Without types, if I have the code `a = foo(x=1)` then I have to hunt down the source file for `foo()`, which likely just returns `bar(x)`, so I have to hunt down the source file for `bar()` to figure out what the hell its return type is, and so on and so forth. With types, I just look at the type signature for `foo()` and I'm good to go (and again, editor integration means that I don't even need to look up `foo()` at all!).
> I write Python in my day job and I _always_ start with types.
It depends of the project. If you write a lot of flask/django code, writing the types is not that worth it except for a few functions/methods.
> Without types, if I have the code `a = foo(x=1)` then I have to hunt down the source file for `foo()`
No, you just hover the function and get the help() out of it in most framework and libs. Again, if your code is mainly using a well define, documented and popular framework/lib/api, that's not a big deal. And it certainly doesn't require YOU to add types.
Or if you write a program that is contained in 1 to 5 files top. Not use for types.
Or if you are writing your program in jupyter.
And you most likely copy a snipet from the doc anyway. After all, if you see that the function you want to use return a AbstractTranscientVectorServiceFactory object, you can't do much with the information without the doc anyway.
But let's be real, most functions in Python are named pretty explicitly, and return things that you expect like "iterable of numbers" or "file like object yielding utf8".
Types are particularly useful in the cases if you are in a big project with a lot of custom code or in a domain either very complex or that you don't master very well. They are a good for of safety net and documentation at the same time.
But they come at a cost and it's a good thing to be able to choose.
> No, you just hover the function and get the help() out of it in most framework and libs. Again, if your code is mainly using a well define, documented and popular framework/lib/api, that's not a big deal. And it certainly doesn't require YOU to add types.
If the help or comments tell you the types of arguments and return values, that is just static typing in the form of comments. Even more verbose than language level type annotations, yet much harder to parse for editors/IDEs/linters.
> No, you just hover the function and get the help() out of it in most framework and libs.
There are no editors that can reliably deliver type information. The ones that come closest (PyCharm and YouCompleteMe) are otherwise very poor editors and resource hogs (the former) or nearly impossible to set up correctly (the latter). And neither is of any use when I'm reviewing someone's code on Github or debugging over ssh.
> Or if you write a program that is contained in 1 to 5 files top. Not use for types.
Types are definitely _useful_ for small programs, but you're right that they're not _necessary_ to the degree that they are for larger programs.
> And you most likely copy a snipet from the doc anyway.
This... is not the kind of programming I do. Although it may explain a lot about our difference of opinion on the topic.
> But let's be real, most functions in Python are named pretty explicitly, and return things that you expect like "iterable of numbers" or "file like object yielding utf8".
Ah yes, the get_values_as_iterable_of_numbers() function. :) Let's be real, virtually _no_ functions are named this way, and even if they were, the typing syntax is surely a better way of facilitating this information. More importantly, it still doesn't tell us anything about the types or number of the arguments. Lots of popular Python libraries (Pandas, Matplotlib) take ridiculous combinations of arguments (two strings and an int sometimes, but other times its an int and a float and a file handle, and if it's called on a Tuesday in April then you can omit all int args). If they had to appease a type checker, these libraries would certainly be much more usable.
> But they come at a cost and it's a good thing to be able to choose.
There are tradeoffs in many areas of programming, but typing is a clear win. Specifically, what is the cost you mention? The type checker won't let your type documentation grow stale? Or perhaps it makes it hard to write clumsy signatures like those in Pandas and Matplotlib?
I'll will also learn because the language is constantly evolving and there's always new toys to play:-)
I program Python for 24 years now. It is my preferred language, but just recently I could go back to develop in it. It is impressive how much new idioms there are to learn.
Yeah, it just needs to work on its tooling and library story. Last time I tried, the OCaml toolchain was such a big pain that the Reason community basically told me to give up and compile to Node. And then there are relatively few native-ReasonML libraries, so you have to figure out how to integrate with OCaml which usually means learning how to _read_ OCaml without clawing your eyes out (I'm only sort of joking).
I'm rooting for Reason, but it has a few nontrivial hills to climb before it's practical.
That's encouraging to hear. Unfortunately I don't do much frontend web development, but hopefully if the frontend web-dev story catches on then the backend will follow.
If the question is "why choose Python" or "why choose JavaScript", then I think you're missing the point. Python is simple and beautiful and highly productive to work in. JavaScript is ostensibly the only language that you can use in the browser without a compilation step (to JavaScript). Just because typing is added separately doesn't negate all of the other benefits of these languages. Hell, if all programmers cared about was type safety we'd all be writing Rust for every project.
> If the question is "why choose Python" or "why choose JavaScript", then I think you're missing the point. Python is simple and beautiful and highly productive to work in.
Well, it depends on the problem! If you’re working with a lot of data structures, or with bytes and serialization, compiled system languages with static typing are going to be productivity boosts over python. Languages aren’t everything, but there are definitely poor language/problem space fits.
> If you’re working with a lot of data structures, or with bytes and serialization, compiled system languages with static typing are going to be productivity boosts over python.
Python has fantastic, expressive and productive libraries for those kind of problems. Unless you have some performance issue, I can't see how you are going to be faster than that.
I think languages like Go are changing that. Most of the statically types languages have been very verbose and often more lower level than people like. If you are building a new web service, python, ruby or JS are very attractive as they help to get something out of the door very quickly. I think Go hits the right spot here between verbosity and safety/expresivness, and a lot of new startups are choosing Go for things they would have built in Python or Node. I think this will only improve as more dynamic languages start adopting static typing and most static languages start adopting things like type inference, etc.
You make an excellent point here that I don't see articulated very often. The Landscape of Popular Languages, let's say C/C++/Java/Python/Ruby/JavaScript, has a big gap in the middle. You have good choices between:
1. lower level "systems" oriented languages with static types, usually compiled, like C++. You get lots of flexibility and direct access to primitives. Static types help wrangle big codebases. Generally suited to large projects.
2. higher level "scripting" oriented languages with dynamic types, usually interpreted, like Python. Writing code for most tasks is easier. You give up some stuff you'd want for projects like operating systems or databases. Most projects aren't operating systems or databases, so that's usually a good tradeoff. Generally suited to small projects.
The problem is that lots of projects are medium-ish. You set out to build your web service backend or whatever, it would be a pain in the ass to write in C++, so you use Python. Getting it working is quick and easy. A few months later it's big, complex piece of software and working on it in Python is a pain in the ass. You can't win. What you really wanted was a language that's "easy to write" like Python, but with static or optional types, maybe better thread handling, and at this point the interpreter isn't doing much for you so it might as well be compiled. There are tons of cases where you just want a "better C" or "Python but faster and with static types", and for the longest time the Landscape of Popular Languages just had a giant hole there.
We needed that space filled and Go delivered. I'm usually very critical of Go, but I can't hate on it for being the wrong kind of language. It's definitely the right kind of language for these "goldilocks" problems that aren't too high or too low level, too big or too small. Part of being a good programmer is understanding that languages are tools, and you need to pick one that fits your problem. Go deserves all the success and praise it's gotten for being a language that fits actual problems.
These gradual type checking frameworks allow migrating massive code bases incrementally. Doing a complete big-bang rewrite into a different language isn't feasible (for the obvious software engineering and business reasons).
So you can introduce a type system in a module, but you can’t write new version of that module in a different language? To me these seem comparable in scope.
They are in no way comparable in scope. Introducing a type system gradually doesn't break any compatibility, within the module or outside the module. It doesn't require you to understand what the legacy code is doing. Rewriting in a different language also means different libraries, different glue code, different interfaces, different everything.
I've been adding TypeScript types to a bunch of JavaScript code recently, and it really is much safer and faster than trying to move to a different language. As long as you are only adding types, you don't have any chance of introducing a bug, since the types just compile away, and plenty of real-world code (especially untyped code) tends to have subtle details that you might overlook if you're reading it for the first time.
Another thing to keep in mind is that type annotations can be done incrementally. You can't take 1000 Python files and port them to Go one by one, but you can add types a little bit at a time with a completely usable codebase at every intermediate step.
The rigor and concepts and generics and interfaces required to properly use staticly typed languages at scale are not always necessary. It's nice for it to be a "warning mode" when you want it, instead of having to design and build that from the beginning.
I guess it comes down to a difference of philosophy. Never in my life have I ever felt compelled to shove an object of the completely wrong type into a function and see what happens. In the overwhelming majority of cases, the answer is going to be "it crashes", so there is no reason to do this.
The point of type-checking is that the function needs to work on a duck, then there is no point to ever pass it anything except a duck. In fact,the compiler should not even let you pass it something that's not a duck, because it's so pointless. That's literally the start and end of static typing, and if that's "rigorous" then yes, the whole point of static typing is to introduce this very basic level of rigor into your codebase. Because it's not going to work regardless of whether it passes the compiler.
Pretending interfaces do not exist does not actually make them go away. There is an interface there whether you explicitly enumerate it or not... even duck typing will fail if you try to call duck functions on something that is not a duck. Dynamic typing is not magic, it's the equivalent of passing everything around as Object or String in a static language. And that's an anti-pattern.
If you just want something to compile, you can pass in null-values of the appropriate type.
Now: there is a valid complaint that Java in particular really embraces the architecture-astronaut philosophy where everything is an overly-abstracted AbstractSingletonProxyFactoryBean (a convenient superclass for FactoryBean types that produce singleton-scoped proxy objects!). But usually it's fairly simple to wall that badness off from your actual business logic.
>The point of type-checking is that the function needs to work on a duck, then there is no point to ever pass it anything except a duck.
If I know I'm only going to pass ducks, and the software is quick and dirty and non-critical enough that it doesn't matter if I accidentally pass it a goose, then I don't want to have a general contractor standing next to me developing saying "make sure that's a duck!"
> If I know I'm only going to pass ducks, and the software is quick and dirty and non-critical enough that it doesn't matter if I accidentally pass it a goose, then I don't want to have a general contractor standing next to me developing saying "make sure that's a duck!"
There is no situation that is so "quick and dirty and non-critical" that you would want an invalid function invocation that could never, ever possibly succeed.
Again, if you just want a dummy call while you're refactoring so that things compile, pass in nulls in those parameters. But there is literally no reason to ever pass totally invalid but real data to a function.
I'm literally at a loss for any situation where you would ever pass an apple to a function that expects a duck, and think that's not just a valid construct, but a positive one that a language should encourage. It just boggles the mind how stupid that is.
Guess people just hate nulls that much, even as a parameter to a dummy stub, that they're willing to give away type safety.
If you really, really, really want to do a construct like that in a typed language, you can always just do "myFunc((Duck) myApple)" to pass the apple as an instance of type Duck, but if a duck is not an apple then that's guaranteed to fail at runtime, just like in the dynamically typed language (because dynamic typing is not magic).
If am writing something quickly, and it's a small project or test, and I might be testing out whether I want to pass a single value or a list in my workflow, I don't want the rails on constantly. I don't want to guarantee safety by ctrl+H-ing my "str" to "Iterable" constantly. Move quickly, break things, get the product out. At least, when the product is a quick and dirty tool and the options are "spend 30 minutes to get it built" or "don't build it".
> The point of type checking is that it has to be rigorous, it doesn't do anything for you if it doesn't check types.
I don't always need to check types. I don't need to know that isReady returns a bool. It clearly returns a bool. This idea that type checking has to be absolute is because in statically typed languages it does, not because that's a forgone conclusion.
> Static typing is extremely useful for knowing what things return - names are not.
Only if you completely ignore convention (that is prefixes return bools) then, sure, it's not useful. But if you just want to break conventions, then all of this is moot because you are guaranteed to do stupid stuff outside of that.
Even if you don't want to break conventions, you might do it by accident. If you don't have a compiler (or a static checker of some sort), there's no one there to keep you consistent.
You are assuming that your usage of isReady will be flawless every time. What if you call a function updateUser("username", isReady()) but it turned out you remembered the order of arguments wrongly. Then the type checker will tell you as you can't pass a bool to a string argument and vice versa. This type of error is super common in %-string formatting.
It won't help if all the arguments have the same type unfortunally but at least it catches something. Just like unit tests, they won't catch everything so the more checks we have and the earlier we run them the less risk there is something slips through to production.
With flow, you just gradually add typings and fix the resulting type errors. It's way easier to slowly integrate types file by file rather than rewriting everything.
Moreover I think that at the time there were no statically typed languages that targeted web.
There are many reasons. Some positive ones are: unnecessary complexity for the initial project, prototyping, exploratory analysis for machine learning/data science, etc. Some negative ones are: fear/ignorance about complexity, incorrect approach to testing (e.g. preference for many fine-grained unittests that effectively act as pseudo-compilers and type checkers under the mistaken belief the code is being tested), incorrect understanding of the tooling/operational support required, etc.
Sometimes you find yourself with a legacy codebase. Other times you find yourself with a team that bucks hard at the thought of a statically typed language. Politics is hard.
I'm using Flow but I'd recommend TypeScript. I love Flow but TypeScript just seems to be more seriously maintained and less buggy. I've been waiting some bug fixes for 2 years (like all the object destructing and spread issues[1]), but they prioritize the Facebook private internal roadmap before anything else (like they improve the performances in almost every patch, but it's useful only for FB and its millions of lines of code). So yeah, the support is kind of inexistent and it's frustrating. When you find a bug, you have to rewrite your code in another way to workaround…
On the other hand, I don't agree with some of the comments here. For example, Flow is not terminal only at all, I never use the terminal to run Flow. The editor integration is totally fine, especially in Atom and VSCode.
JS with flow is way better than JS without flow. It prevents a whole class of errors, and you can basically opt-in and opt-out of the type system at any time if you're having trouble with it too. I wrote a blog post about it a while back: https://www.aria.ai/blog/posts/why-use-flow.html
That being said, while I started out using Flow, TypeScript just has way more community adoption and better tooling. So at this point, I usually recommend TS over Flow to most people. But using either of them is way better than writing just regular JS code.
Typescript has way better editor support, and is faster on large projects. Flow is mostly terminal only, and required a really annoying syntax in it's config file to exclude all node modules.
That being said, Flow is better then no typechecks, and it was half a year ago that I looked, stuff might have improved.
I have struggled in the past to learn modern C++. I think the language is pretty cool, but couldn't find good guide in learning about them.
Having used Rust for a year or so, now I look back at these features and they seem quite natural. I have to say the documentations and tutorials from Rust community is great. It might be a detour, but now I feel much more comfortable reading modern C++ blogs and watch this video!
It may be worse than 996. WeChat easily penetrates employee's life after 9. A message from your boss that requests something urgent, and you begin working again.
Hey! I actually did see this before because I was searching for exactly that. I think I found it helpful in a specific way - maybe I should try using it for longer to see if it sticks in my mind. I think that's what I'm really lacking - a kind of mental visual short hand that holds together in my head.
Second his book. The best part of his book in comparison to other cooking books is...a schedule (instead of the duration). Start mixing flour and water at 9:30 AM and then do X at 10:30 AM, etc, etc, and you will get the bread at 5 PM for dinner. Simply following the schedule ensures sufficient time for the yeast to develop and the dough to rise. I have never failed with his schedule and friends think the bread is competitive with what's purposed.