God I love the language. The only language, that allows my thoughts to flow alongside writing code that allows my thoughts to manifest.
I am well experienced with C# as well, but something about statically typed stuff (I worked with C# before the dynamic stuff wasn't added to it) breaks the flow of thoughts.
With python, it's like designing systems on paper. Friction-free.
I absolutely love the free form in the prototype phase, but once I've got that one nailed and want to make it maintainable... well, I always miss it at that time.
However, quickly iterating through to a solution and then optimizing it in a static language is a workflow that can be adopted. However, that may be necessary for only the most critical parts of an application.
With software development moving towards distributed computing, there is a lot of breathing space for languages like Python.
For unfammilliar codebases using MonkeyType is now a option too.
Maybe a flag to the interpreter that would raise an exception each time it detects an inconsistency at runtime. I can imaging turning this feature on in a staging environment.
Truth be told, I am not a Python fan. I am seeing it take over in my industry, because it's superficially 'easy' and it's popular. The lack of static typing only later becomes a big problem when large codebases start to appear with many contributors.
Haskell's effect typing also helps us. For example, for reproducible calculations, it is critical that no data is pulled-in via a backdoor (i.e. a side effect). Even reading and using the current system datetime is something we want to prevent. This can be expressed in the types using Haskell.
And yes, in such a situation, Python will not be an easy fit.
Thanks a lot for sharing the info. Have been wanting to learn functional programming for a long time now. Specifically, I am planning to build computation systems based on Haskell, Scala, etc which sit behind a Message Queue server. Just to isolate the computation part from other mundane activities like HTTP request processing.
I'm going to volunteer an answert to a slightly different question. "What sort of problems are strongly typed languages suited for?". They are suited for general purpose programming.
Even when prototyping, I find that nailing down the data structures from the get-go makes subsequent code-writing much easier. A lot of times, the code kind of falls out naturally when you've figured out the data structures you're working with.
Strongly-typed languages give you a nice way to define data structures.
They are "easy" in that sense which makes them popular with a subset if developers, while another subset loathes the terrible language services/tooling.
Incidentally many dynamic languages seem to have attempted to bolt on some faux type system; python type annotations, phpdoc, jsdoc, type specs, etc, etc.
I think the efforts of adding type/type hints to python are interesting - but there's a tension between "weee! Look at me ducktyping, metaprogramming all the prototypes!!"-design and leveraging types as part of your design. Haskell/f#/ml are great languages, but they feel very different from python (ml maybe less so,but afaik there are no full featured implementations with areasonable standard lib...).
If Python is the starting point, I think there's probably four approaches that makes sense if python ends up being limited (in part due to lack of typing): move to a language like Julia, proto-type in python; re-employment in go, prototype in python; reimplement parts in cython and/or rust, add type hints on top of python.
[ed: almost forgot, secret option number five: use restricted-python and the pypy framework to implement a language suited to the problem domain..]
Except maybe for things that are actually pointer+offset (which I think very rarely makes sense in high level languages/most ADTs).
In fact, I think for situations where 0-based indexing makes sense, I'd prefer "memory_area+offset" rather than "pretend_collection_type[offset]".
I also usually talk about "the first character" of a string, or first word of a sentence; not "word at zero offset from start".
So yeah, I think Dijkstra's wrong on this one (or rather he has some very strong opinions on greater-/less-/-and-equal-to, and which are natural - for which I have little sympathy outside of abstract discrete math papers).
http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EW...
It's also my understanding that the TS community wants to replicate the mypy model where typechecking and compilation are separate steps; by adding a typescript compiler with no type checking to Babel.
> granitosaurus 3 hours ago [dead] [-]
> There's also nim, which is rather new and not yet v1 worthy but I'd say it's still a worthy contender to the "closes thing to python with types"
I think nim looks nice, and have some very python like qualities. But while it's statically typed, I think it's more "python with native compilation", than "python with types" - in the sense of how the typesystem help with program design.
Python + pascal are by far the ones I enjoy the most. I do a lot of F# now, and I like it, except, is not a good pascal!
i.e: The thing that bother my most of F# is that by default it not force to anotate types. One thing good about pascal is that is VERY EASY to figure out almost any line you read (without IDE help. Infurate me that F# know, but hide the knowledge to me!). With python is easy to infer the operations but not the data (ie: easy to read "I'm iterating" but not "and is a array of ints")
I could anotate a lot on F#/Python but is not idiomatic. This mean, that a lot of times I'm lost with F# in the ways is with python, with the worse thing that the infered stuff get crazy hard.
But, IMHO, python and pascal are in the TOP of truly well designed languages, where the sum of all the small things match well
What does make it easy to build big systems is semantic typing. I.e., the ability not just to declare a machine type, but to declare the actual assumptions made by any component about its inputs. In some low-level code those assumptions are about machine types (argument i must be an 8-bit integer, and s must be a string). But in other cases the assumptions are about what the argument represents (argument s is a string denoting a filename (not just any string), argument n is a number between 1 and 36.2 (regardless of machine type)). Any given component makes some assumptions about what it can handle, and if you can easily declare those assumptions and validate against them, then the component is easy to read, easy to understand, easy to use, safe against user errors, and easy to implement (as you don't have to write any code to handle conditions not allowed by the declarations).
The beauty of Python is that semantic typing can be implemented very naturally within the language itself, which is crucial because it has to be extensible to handle any given domain's objects if it is to be of use. There are a variety of options, but my own package Param (https://ioam.github.io/param) provides support for semantic typing, and if you look at some of the examples there you should be able to get a feeling for how you can have the best of all worlds in Python: freedom where you can handle it, constraints where you want them, and everyone being up front about what they are doing in a way that makes big teams able to work freely with whatever other people come up with.
Refinement types can statically capture range checks and other similar assertions. There is a project to add them to Haskell (Liquid Haskell) which is already quite useable.
Of course, static types are machine checked prior to running the program. None of your Python "types" exist until runtime, by which point it is too late. The program crashing due to an assertion failed error is logically still a crash.
We will have to agree to disagree on the roll of static types when building large systems. I have also spent over a decade working on very large codebases. The more "dynamic" a system was (late binding, reflection, string-based lookup, variants), the harder it was to statically reason about the code and avoid introducing errors. In a fast-paced business where hundreds of people are changing the same codebase daily, I do not understand how one could stay sane without static types. Python was never designed with such use-cases in mind.
Polymorphism is for addressing exactly that objection.
1. The KeyboardInterrupt exception for SIGINT. Whoever came up with that idea destroyed the credibility of the entire interpreter. Python falls flat on its face to me because of this one design choice. It's impossible to write a Python script that will not dump a full debug stack trace if you send SIGINT (ie: Ctrl+C) before the first line of your script is reached. That is, even if your very first line of code is a try/except block intended to catch KeyboardInterrupt, a SIGINT early on will still fail spectacularly at some point during Python's internal startup. Python runs a lot of code before turning control over to your script and it's simply not possible to, from within Python, catch these signals.
In order to provide a professional piece of software to clients that will not dump debugging gibberish to the terminal, one must wrap every single Python script with a shell script or small C binary that catches signals and proxies/rewrites SIGINT as SIGTERM, in order to avoid KeyboardInterrupt entirely. Something as fundamental as signal handling having been botched to this extent is frustrating.
2. The asyncio module. They screwed up the async implementation in the earlier phases, and the hacks that have been implemented in an attempt to improve the situation are grotesque. The state of async in Python is confusing enough as it is, but if you happen to run into one of the edge cases where the ways in which they've hacked the core of the language to make room for the async stuff affects you, you're in for quite the ride.
% python -c pass
^CTraceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.py", line 62, in <module>
import os
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.py", line 400, in <module>
import UserDict
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/UserDict.py", line 83, in <module>
import _abcoll
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_abcoll.py", line 9, in <module>
"""
KeyboardInterrupt
There was some discussion about this at https://bugs.python.org/issue14228 , with strong pushback from some of the core developers.One of the workarounds was to do:
python -S
to avoid importing the site module, then set your signal handlers, then import site manually. In that case the only output, if caught at the wrong time, will be the message 'KeyboardInterrupt'. This isn't quite what you want, but it's a lot closer.(Another request for this feature is at https://bugs.python.org/issue24261 .)
If you are still working with Python, and still want this feature, you might contribute to that second thread. The first is rather contentious.
I never noticed that but now that you say it...
There should be a way to pass an option to Python so that if you do 'python --early-sigint "message"' it prints the message for an early sigint.
You should post that to the python-ideas mailing list. It's a long and tedious process to get everyone on board by writing mails, but it works. Pretty much everyone can do it.
I suppose you could avoid the possibility of a name clash if the interpreter maintained a hidden, name-mangled reference for you...?
Personally I think it's a bigger problem that python isn't all that well suited to functional programming because of lack of tco etc (see slackness python etc). But I understand the design decision.
While they are not true anonymous functions, I have yet to stumble on a scenario where a context manager did not fit the bill. They're easy to create - nothing more than a try/except/finally with a "yield" call to execute... you guessed it, essentially an anonymous function block. It's a little mind-warping the first time through, but it winds up creating clean code. PEP 343 is a good source to learn more.
And you can do composition easily, that's the main seller for me.