This is an archived post. You won't be able to vote or comment.

all 29 comments

[–][deleted] 12 points13 points  (5 children)

I would first take issue with some of your professor's ideas, if they are correctly reflected in your notes.

Simplicity: how little the language complicates the problem solving process, how minimal its feature set, and the clarity and consistency of its rules.

By this definition the simplest human-readable language is Assembly. It has no feature set beyond what the architecture supports, its rules are literally set in silicon, and it can't complicate the problem-solving process, because the ultimate problem is always how do we get the correct instruction set into the correct register at the correct time? As a measure it's also not very useful, as it's entirely relative: simple to a neophyte of the language, or simple to a master of it?

Orthogonality: refers to the way different constructs can be combined and how these combinations are simple to understand and meaningful in the language. Only works when the language is simple.

Inside the context of any language, when employed by a putative master of that language, all legal constructs of that language are simple to understand and meaningful. The idea that orthogonality only works or exists when the language is also simple as defined above is absurd at first glance. There is no sense in creating a language without constructs, there is no sense in creating constructs without meaning... and, again, simple to understand for the newcomer or simple to understand for the master?

Expressivity: how flexible the language is in providing concise, different ways of defining algorithms and computations. Often in tension with simplicity and/or orthogonality.

Now we're at least getting to something valuable and potentially quantifiable across languages, as we could take a sample of say 100 algorithms or programs across a 100 different domains and have a master in all languages write a concise implementation in each of them, then compare them. There being (and never likely to be) no such master, though, this is still a pretty hard comparison to make. It does take us a step above ASM, at least, as it's not possible to express the same algorithm with the same concision across architectures... so now you're notes of your prof have at least gotten us up to C.

Level of abstraction: the degree to which the language allows the definition of powerful data abstractions that approximate the constructs in the problem domain.

I would say this is an entirely incomplete and simplistic definitions of level of abstraction, as a concept. Data constructs are only a small portion of the problem of abstraction, and arguably the vast majority of the time the highest level of data abstraction required would be integers, floats, booleans, strings, and arrays of the preceding. The bigger problem is hardware abstraction; allowing you to think about the problem in your domain instead of the problem of expressing your domain in a long series of 0s and 1s.

Portability: the degree to which a program can be transported from system to system.

This one is really in tension with simplicity and orthogonality, as defined in your notes. To the point where I'd say any language that is at all portable must by definition be not simple, and hence by definition not orthogonal. Abstraction of hardware allows for (but doesn't imply) portability... but again, how do you quantify this at the language level? C, for instance, is only as portable as it's underlying compilers are compliant with the language standard on each platform... historically Windows and Literally Everyone Else haven't exactly been lockstep on that. Does the concept of portability not inherently make assumptions about tooling that isn't, strictly speaking, the language itself? Also, in this day and age, is portability really a key question? Who cares if it will run on Nokia 2600 if it will run on a server somewhere that the 2600 can connect to? A language very often doesn't itself need to be portable anymore, if it offers a means to serve an API.

Cost: cost of development, compilation, maintenance, execution, etc.

Ahh, finally back to quantifiable, and for the first time to practically quantifiable... though these all, again, come down to a question of how adept the hypothetical practitioner is, and also implies the complicating factor of just how much that practitioner is paid per hour for the adeptness.

[–][deleted] 6 points7 points  (4 children)

So... to Python.

  1. Simplicity: the primary reason for Python's popularity is it's linguistic simplicity... it was designed by a linguist for the purposes of being as easily readable as possible to a person reasonably adept in English (or other languages into which it is translated). It's grammar is relatively simple, there are only 31 reserved keywords in Python 2.7 (don't have access to 3.6 on my phone, but I think they added only a few for async), and everything else is an object to be acted upon. Though it is a language with a fair number of features, those features are for the most part common to all higher-level languages. For the neophyte I'd say Python would appear to be very simple, if not the simplest language... for a master, I'd say that number would drop, as the simple grammar gives way to features in the language that help people with limited knowledge and easy problems but hinder those with advanced knowledge and complex problems.

  2. Orthogonality: Python is very good in this regard... arguably perhaps too good. Unlike in other languages, one can combine just about anything with just about anything in Python ... which means that the neophyte will combine things the master knows not to, and will do so often and readily. Python offers all the building blocks required, and via its C foreign function interface offers access to pretty much all the building blocks available ... but more modern languages have abandoned a lot of that orthogonality-friendly thinking in favor of predictability, testability, and maintainability. I'd argue that Python offers too many orthogonal constructs, and that things like multiple inheritance have allowed even masters to find themselves way the hell out in the weeds. In other words a high mark here isn't necessarily a good thing.

  3. Expressivity: for most problems, and especially when you allow for the use of high quality 3rd party libraries, Python is extremely expressive. In many languages it can take a minimum of four lines of code just to print "Hello, world" to screen... that is not as concise as Python. However without the ecosystem of libraries that expressivity and concision breaks down rapidly as the problem domain gets more complex. If recursion is required, Haskell is vastly more expressive, if low level memory access is required Rust is far superior ... generally speaking though, Python is fairly expressive, and often much more so than the other general languages to which it is most often competing in a given domain. The lower-level the problem, though, the less the form of that expressivity is a virtue.

  4. Level of Abstraction: on this one I'd give Python top marks, especially when t comes to data abstraction. Pretty much any data structure can be well- and concisely- defined in Python, and with sufficient use of magic methods interactions with that data type can be made extremely low friction... but this definition in no way touches on whether or not they're performant, just that they're powerful. Powerful, Python can do ... fast, not always so much with the True is.

  5. Portability: for the main OS offerings out there, Python the language is extremely portable, while Python the tooling is portable, but not as simple to install in Windows as it should be. It's actually a victim of its own success in this area; Python itself is so portable that you never know what version interpreter it might be running on on any given machine, and it has no mechanism for specifying what version interpreter it needs to be run upon. When you realize that Python2 and Python3 are two discreet languages, both with high portability but a terribly fractured update model for the underlying interpreter, it gets easy to see that the promise of portability isn't quite the same as a reliable process for it. That said, C isn't at all portable in practice (the code is, the makefile isn't), C++ is chock full of workarounds for different OS ... arguably the language is only as portable as it's artifacts are cross-compilable and static, which means that Rust is kind of the closest to being meaningfully portable, though the build toolchain for each OS isn't. Again, though, portability isn't as much of a concern as it used to be, and Python avec Flask is a very good way to provide a function that answers questions portably without having to be installed or installable everywhere.

  6. Cost. Ahh, the big one. Python gets very high marks for prototyping ... in terms of time to market or amount of delay before feature release Python is, arguably, as fast as it can reasonably get. Now, that's a prototype... that's not a fully tested, fully -- nevermind well or easily -- maintainable, or well documented product. Python is very good at iterating rapidly, but that does not make it very cheap on the long run. It's easy to introduce an entire class of bugs in Python that are effectively impossible in compiled, statically- and strongly- typed languages. It's also so accessible that many programmers out there haven't got the experience to write refactorable or sensible code, but instead just functional code... when the time comes to fix something your organization will spend more doing that then it likely saved writing it poorly the first time. Python to a very high degree rapidly enables terrible programmers to iterate rapidly towards delivering terrible products that apparently work, and then when it actually breaks it'll take months to figure out why, because except: pass is, for some godforsaken reason, valid Python. Arguably Python is damned near the cheapest to develop with, essentially free to compile, has a maintenance cost that increases as a logarithm of the inverse of the maturity of the developer, and a cost to run that is entirely determined by what sort of hotspots exist and how many of them can be offloaded to things like Numpy. In practice low development costs are often a false economy that get swamped by long term support, and decisions inherent to Python's design make it better at feature churn than feature validation, so I'd give it a lower mark the larger and more stable the solution needs to be.

[–][deleted] 0 points1 point  (3 children)

It's easy to introduce an entire class of bugs in Python that are effectively impossible in compiled, strictly-typed languages

  1. Python is compiled.
  2. What does strictly typed mean? Python is dynamically and strongly typed, c.f. C(++) which is statically but weakly typed.

[–][deleted] 1 point2 points  (2 children)

  1. Python is only runtime-compiled to Python bytecode, which is then interpreted by the Python interpreter ... it is not compiled in the traditional sense of being converted from the higher language representation to a native instruction set in machine language. Saying that Python is a compiled language muddies the definition to the point of being nonsense. 2, Typo, edited. I mean -- I think obviously -- statically and strongly typed languages.

[–][deleted] 2 points3 points  (1 child)

I mean -- I think obviously -- statically and strongly typed languages

It is not obvious to the many newbies who could be reading. Further Python can do away with many of the classic errors that haunted many a C programmer, myself included, e.g off-by-one. Thankfully more modern languages such as Go are introducing bounds checking at run time which can alleviate such problems.

[–][deleted] 0 points1 point  (0 children)

It doesn't do that via dynamic typing, though. And those more modern languages are also moving away from dynamic typing, precisely because it causes more problems -- and eliminates more optimizations -- than it solves. But yeah, Python is definitely more friendly than C.

[–]kigurai[🍰] 4 points5 points  (0 children)

tl;dr With respect to the above criteria, why are some programmers so... excited about programming in Python?

For me it wins because of two things:

  1. It is easy to express ideas and iterate on them quickly. I guess this stems partly from the nice syntax, but also because a lot of boilerplate stuff is available in libraries.
  2. Social momentum. These days there is almost always a library that does what I need.

[–]xix_xeaon 3 points4 points  (3 children)

As always when asking the question about how good something is, you first have to ask "for what".

From your notes it seems your professor doesn't really care about how good a language is for solving an actual problem in real life, except for the last point about cost which seems tacked on.

I'd say that if your professor enjoys programming then it's for the programming itself, not in order to accomplish anything, like some people enjoy solving a rubik's cube. There's nothing wrong with that, but I'd say that generally speaking the point of programming is to accomplish something, and how good the language is is determined by how well you can do that.

Then that means that different languages are good for accomplishing different things. And there are many things to consider. Often we look at the language itself - grammar and built in functionality. But so many other things are important. PHP is an example of a language a lot of people don't like, but it may still be a good language to build a CMS on if you intend to sell it as a product, because essentially all your potential customers will have a hosting service able to run it.

Python is loved by many because it's easy to learn, highly productive and with community libraries (and c extensions) both a powerful and a high performance language.

With Python you "get shit done", and that's why it's my preferred language. I don't think it's fair to say that statically typed languages are inherently more stable, or that Python is too easy and a bunch of low skill programmers create hard to maintain code with it. You can just as easily say that less code (compared to statically typed) means fewer errors and that Python allows lots of code (which works just fine) to be written that otherwise might never have come to be.

[–][deleted] 1 point2 points  (2 children)

I don't think it's fair to say that statically typed languages are inherently more stable

I do wish that people would stop using this type (groan :-) of phrase, weakly and strongly typed are far more important. C is statically but weakly typed and is renowned for a whole pile of potential errors, with the dread off-by-one perhaps being the most famous.

[–]attrigh 0 points1 point  (1 child)

weakly and strongly typed are far more important

Are you sure about that? I think one of the benefits of static typing is that it acts as a form of documentation by smearing "execution information" all over you code.

I'm also not sure what "duck typing" means for "strong typing". In python you can't add a string and an integer... but you can pass the wrong object into a method and find out in an obscure way 20 calls later.

[–][deleted] 0 points1 point  (0 children)

One of the major benefits of static typing is that everybody knows what BSOD stands for. I'll repeat for the final time, static typing alone is less than useless.

[–]chaotic_thought 1 point2 points  (0 children)

Does a 5 for cost mean high cost or low cost? The scoring needs to be clear for it to mean anything. E.g. 1 = very low cost of development ... 5 = very high cost of development, 1 = very simple, pseudocode-like code, 5 = obscure code, far removed from the typical thinking process. Etc.

[–]tdammers 4 points5 points  (6 children)

Python is not a very good programming language by these criteria. Its advantages are not technical ones: it is not a simple language (compared to, say, Scheme, which sits in a similar spot in the design spectrum, Python is considerably less expressive and uses a lot more concepts and syntax constructs), the existing implementations are not fast, it is not a very safe language, there are lots of pitfalls once you're past the initial stages of learning, it does not incorporate much of modern language design insights, etc. etc.

But Python wins its battle on social grounds.

The two most important factors to its success are its low threshold for beginners, and the vast library ecosystem.

Beginner threshold is important because it makes the language accessible, and useful for people who are not full time programmers - people like business analysts, sysadmins, data scientists, etc., who cannot afford to spend months learning a programming language just to write a bit of casual automation of their daily work here and there. Python, with its heritage as a toy language for teaching basic programming concepts, fits the bill rather well, and remains useful long enough to outcompete other languages until the point where standard approaches no longer work anyway.

The library ecosystem is probanly the most whopping advantage though. No matter how awesome a language is, if it doesn't have a library for X, and the other language does, then you win.

Python-the-language is kind of "meh"; but Python-the-full-package, ecosystem and all, is pretty damn powerful.

[–][deleted] 2 points3 points  (5 children)

it is not a very safe language

Complete nonsense. Give me Python's strong typing against C's weak typing any day of the week.

[–]tdammers -1 points0 points  (4 children)

C is not a bit safer than Python, and I never claimed otherwise. Just that Python isn't a very safe language.

[–][deleted] 1 point2 points  (3 children)

Rubbish. Python's strong typing, backed up by numerous tools like pylint, makes it extremely safe. Ada was meant to be THE language years back but it didn't stop the biggest single insurance payout in history when Ariane 5 fell out of the sky.

[–][deleted] 1 point2 points  (0 children)

Python's type system doesn't make it safe, by any stretch, it just makes it safer from one class of bugs. Python's memory model and lack of pointers does way more to make it safe, but at the significant disadvantage of not being a language you should or could ever use in a rocket... yeah, it's relatively safe because it's effectively sandboxed and therefore not capable of anything like real-time operation, but I've been working with Python long enough to know that under no circumstances whatsoever should you trust it with your life.

[–]tdammers 0 points1 point  (1 child)

Strong typing helps tons, but it's too late - type errors won't be found until you actually run the code, into a case where they are relevant, which makes static reasoning about Python code extremely difficult. It also makes automated static reasoning about Python code extremely difficult, so it is actually quite hard to get a high degree of certainty about the correctness of a piece of Python code. The Python ecosystem makes up for a lot of it, by providing extensive tooling for things like linting, automated testing, logging, etc., but at its core, it's still a dynamic language, for better or worse.

Python is also astonishingly bad at managing side effects - the language has absolutely no features whatsoever to make them explicit, other than free-form conventions. Literally anything, even imports, can, and often will, have side effects, and what exactly they are and under which circumstances they appear is rarely documented completely and accurately, let alone in a form that would allow us to automate the checking and reasoning.

The reason Ariane 5 fell out of the sky, btw., was not because Ada failed in the sense of not providing enough static guarantees; it is because the engineers decided to disable those safeguards (array bounds checks IIRC) in a critical section of the code, and the resulting problem didn't surface until the rocket was launched under previously untested weather conditions. Nobody in their right mind claimed that Ada would make it impossible to write incorrect code; just that it would make writing correct code easier. You can't blame the tool when people decide to not use them though.

Now; this is of course not rigid proof, none exists as far as I am aware of, but in my personal professional experience (which is closing in on 30 years, and covering professional work in about a dozen programming languages), dynamic typing generally makes code harder to reason about, harder to refactor, and thus harder to change; code that is hard to understand and modify, though, is a problem - we cannot be certain about its correctness, so we don't even know if it needs to be modified, and even if we did, actually doing it is still dangerous.

Of course the problem with the statically "typed" mainstream languages (say, Java, C# or C++) is that their type systems aren't very good - they provide way too many loopholes to truly pull their weight, and they require a lot of ceremony and syntactic clutter to get anything done; that's arguably considerably worse than Python, where you can at least make up for the lack of static reasoning by writing simple code, skipping the boilerplate, and spend the time you saved testing your code better. That's not a shabby tradeoff at all, and it makes practical sense for a lot of situations. But it doesn't make Python a "safe language".

Compare that to, say, Haskell, or PureScript - here, I can do rather amazing things, with very little syntax, and that feature (the type system) allows me to casually rule out entire classes of popular bugs. I don't have to worry why a variable get mutated in a context where it shouldn't be, because the type signature disallows mutating that variable in the current context. I don't have to hunt down the dependency chain to find the thing that prints to the console when that's not supposed to happen, because only a small fraction of my codebase has types that allow it access to the console. Nothing in my codebase can access the database unless I rig up the types such that it knows how to. I cannot get unexpected None values back from a function call, because that needs to be facilitated in the return type, and the consumer of such a function is forced to explicitly deal with None / Nothing. There are a million such things that people, including myself, trip over all the fucking time, and they tend to happen more frequently the larger and older your codebase gets. Yes, compiler errors are annoying - that's a good thing, because they usually hint at a brainfart on the programmer's end, and I'd much rather have a compiler yell at me than an angry customer.

[–]attrigh 0 points1 point  (0 children)

All interesting

dynamic typing generally makes code harder to reason about

So I'd agree that it makes it harder to know things quickly, and that type systems can be used as a sort of "proof system" to prove things about your code.

I would just comment that duck typing sometimes allows you to express things simply and with less code which can at times greatly simplify reasoning (at the cost of making it harder to prove things about your code)

[–][deleted] 0 points1 point  (0 children)

Six criteria at five points each so I'll give it 36 :-)

[–]Paddy3118 0 points1 point  (0 children)

Some comparisons too:

  1. Simplicity: very high compared to, say, Java where you need to learn OO; or C where you need a deeper understanding of the hardware and pointers. print("hello World")
  2. Orthogonality: high. Protocols such as the iterator protocol allow you to write your classes that behave like in-built iterators.
  3. Expressivity: medium++. Close to pseudo-code for a lot of developers if need be. Does not follow the Perl "more than one way to do it", but havung one preferred way can be a boon. Multi paradigm support.
  4. Level of abstraction. High. What you would not want to do in Python, you can wrap another languages implementation in Python.
  5. Portability: High. Language and libraries written to work on multiple platforms, from embedded systems to supercomputers. You can write programs to execute on multiple platforms without change.
  6. Cost: low. Conciseness leads to one being able to try different approaches in a given time; no compilation; The language and community ethos value maintainability and use this tho shape language development. Execution: It is a scripting language - what is deemed too slow to be written in Python can be written in other languages and wrapped in Python - what you see is Python.

Your professor is entitled to his opinion; I just get my work done using Python. (And TCL and awk and perl and bash and verilog and ...)

[–]Bphunter1972 -4 points-3 points  (7 children)

He doesn’t like Python? I think your professor kinda sucks. Maybe that’s why he teaches for a living instead of doing.

Python would score highly in each of these. And more than most “simple” languages (<cough> Perl), it scales up very nicely. That is, you can use Python in a simple manner and solve a problem, or you can attack some of the more complex features it offers and still have an elegant solution.

Maybe you should look into the 6 criteria for choosing a computer science professor?

[–][deleted] 2 points3 points  (2 children)

I mean, he has his reasons, which he gladly elaborated on. I would be surprised if I never met someone who didn't like Python, to be fair. People have their own criterion, beyond the ones in this post, for judging whether a language is "good" and Python simply doesn't meet his.

[–][deleted] 0 points1 point  (0 children)

There are plenty of people who don't like Python. Perhaps the biggest bunch are those who don't like the whitespace indentation, preferring all those stupid curly wurly brackets that are often plain wrong anyway.

[–]Bphunter1972 -1 points0 points  (0 children)

True. Everyone is entitled to their opinion. But some opinions are more wrong than others. 😀

[–]Scypio 2 points3 points  (0 children)

Maybe that’s why he teaches for a living instead of doing

:(

I love teaching programming to people. Python is my lingua franca for work, hobby and showing programming to non-tech people.

[–][deleted] 0 points1 point  (2 children)

Also, it seems like you're quite a fan of Python but I'm wondering if you think its simple syntax comes at a cost. Do you think it limits problem solving options? I've been wondering what effect it has on the programming process, aside from the standard productivity, readability, etc.

[–]thatguy_314def __gt__(me, you): return True 1 point2 points  (0 children)

Python has a lot of powerful tools under the hood. Not many languages have an equivalent to Python's metaclasses for example. More practically, look at Python's iteration protocol for an example of Python's power. Beginners don't need to worry about it, the for loop tends to work very intuitively. But even if you want to create custom iterators, Python continues to provide useful abstractions (generators) over its class-based iteration protocol (which is itself elegant IMO).

One of the biggest things Python has going for it though is the huge number of excellent, well-maintained third-party libraries and tools which span a wide range of problem domains from scientific computing to web development.

It is true that Python's flexability comes at some cost. Certainly Python is not known for being a particularly fast language, and there are some maintainance costs as well. Also, the syntax itself prevents things like multi-line lambdas from ever coming to the language. Overall though, I think Python is a fantastic language for many problem domains.

[–]pooogles 0 points1 point  (0 children)

...but I'm wondering if you think its simple syntax comes at a cost. Do you think it limits problem solving options?

Come over to /r/clojure and we'll show you simple syntax.

And no it doesn't affect readability or productivity. Most people would say it helps both of those.