Translation: Open Source China
www.oschina.net/translate/languages-to-improve-your-python
Original: http://www.curiousefficiency.org/posts/2015/10/languages-to-improve-your-python.html
27 Languages
-
Procedural Programming Languages: C, Rust, Cython
-
Object-Oriented Data Modeling Languages: Java, C#, Eiffel
-
Object-Oriented Derivatives of C: C++, D
-
Array-Oriented Data Processing: MATLAB/Octave, Julia
-
Statistical Data Analysis: R
-
Computational Pipeline Modeling: Haskell, Scala, Clojure, F#
-
Event-Driven Programming: JavaScript, Go, Erlang, Elixir
-
Gradual Typing: TypeScript
-
Dynamic Metaprogramming: Hy, Ruby
-
Pragmatic Problem Solving: Lua, PHP, Perl
-
Computational Thinking: Scratch, Logo
As a co-designer of one of the most popular programming languages in the world, I often encounter a frustrating behavior (present in both the Python community and other fields) where influential members of the community try to instill a fear of “missing out” and use it to drive others to contribute to our community (I occasionally engage in this inappropriate behavior myself, and I’m more easily able to recognize it when others fall into this trap).
While it is beneficial to learn from the experiences of other programming language communities, using fear-based methods to drive action is problematic. Community members, in an effort to attract code contributors, may view members of other communities as competitors rather than as potential allies to tackle challenges together and promote advancements in software development technology. This can also lead to communities rejecting those who prefer other programming languages, treating them as enemies.
In fact, we want to have a richer selection of cross-platform open-source programming languages available. Programming languages are the most important tools of thought, allowing us to translate our ideas into clear terms that computers can understand. If people discover a language that suits their brains and directly solves their problems, that’s great; they shouldn’t have to worry about which language they choose.
Thus, I want to make three specific requests to the Python community and offer a broader suggestion. First, the requests:
1. When we want to motivate our tribe members and enhance community appeal, we should not use fear tactics; instead, we should use pride tactics. When we use fear tactics, such as saying, “If we don’t solve problem X, Python developers will decrease and turn to language Y,” we are deliberately transmitting negative energy to the world of freely contributing code. But if we use pride tactics, we might say: “Problem X in Python is indeed difficult to solve; look at community Y, they have a great way to solve this problem, and we can try this solution in Python to solve the issue elegantly.” Emphasizing “pride in our own efforts” fosters a culture of continuous learning in the Python community and promotes the development of relationships with other communities.
2. Restrain contempt for other programming language communities, especially those that have experts who can solve their own problems without waiting for commercial software vendors to step in. Most of the world’s important problems are not driven by profit (those who want to solve problems are not doing so for wealth, and there are no institutions funding them), so we should encourage and praise those who are actively trying to solve problems, regardless of the technologies they use.
3. If someone we know is just starting to learn programming, even if the language they choose is not one we like, we should support them, as they know better what suits their brains. Therefore, a language that is suitable for us may not be suitable for them. If they start to feel frustrated with their initial choice to the point of losing their motivation to learn programming, it makes sense to recommend programming languages at that time. This advice is also applicable to those of us who have worked on improving network security; for languages that were initially unsafe, our solution is to gradually break down the barriers of language choice by improving the sandboxing features in the operating system, enhancing the security properties of the native system, and improving the default behavior of programming languages. We should not evaluate programming languages based on application security; this confuses beginners. (If someone asks a programming novice to write an unaudited piece of software that is deployed to handle security-sensitive issues, it is not the programmer’s fault, but rather the fault of the person who deployed it without due diligence regarding the software’s source and security properties.)
My broader suggestion is aimed at those who begin to encounter the core assembly of Python and thus start exploring more of Python’s own “thinking tools”.
Part of what we do in the core development process of Python is to leverage the characteristics we understand in other languages to make Python code easy to read and write. This means that learning other programming languages can clarify specific styles and enhance one’s understanding of software development while programming in Python.
To aid such efforts, I have listed below areas for exploration, along with some languages that may provide additional insights into these areas. I have linked to Wikipedia pages whenever possible rather than directly to related home pages, as Wikipedia often provides interesting historical context that is worth exploring when choosing a new programming language as an academic exercise rather than for immediate practical use.
However, personally, I am familiar with many programming languages (and have used some of them to develop production systems). All recommendations include languages I have indirectly learned about (either through reading materials and design documents or from discussions with trusted friends regarding the strengths and weaknesses of a language).
There should be many more languages that could appear on this list, but the specific languages listed here are just a random subset, selected to some extent based on my own interests (for example, my main interests are in the dominant Linux, Android, and Windows ecosystems, so I have omitted the closed but more profitable Apple-centric Objective-C and Swift programming languages, and I am less familiar with programming languages focused on artistic environments, such as Processing. I even need to guess how what I learn from them can guide a Python developer). For a more comprehensive list of programming languages, many factors need to be considered, and in addition to considering how a programming language can guide you to become a developer, the annual rankings of programming language popularity and growth by IEEE Spectrum are also worth understanding.
Procedural Programming Languages: C, Rust, Cython
The default execution model of Python is procedural: we start from the top of the main module and execute one line at a time. All of Python’s support for other data and computation models is based on this procedural characteristic.
C is undoubtedly still the dominant low-level programming language. It is the core language used to implement the Python interpreter and is also the core language for implementing the Linux operating system kernel. As a software developer, learning C is the best starting point to learn more about the underlying hardware on which software runs – C is often described as “portable assembly language” and is commonly used with C compilers as cross-compilers to compile the first applications for new CPU architectures.
Rust, in contrast, is a newer language created by Mozilla. The reason it makes this list is that Rust learns from known industry lessons about what cannot be done in C and is designed to be able to interoperate with C libraries. It achieves the same level of control over hardware as low-level system programming languages, but it uses different compile-time methods for data modeling and memory management, structurally eliminating many common pitfalls that plague C programs (such as buffer overflows, double-free errors, null pointer access, and thread synchronization issues). I am an embedded systems engineer, and through training, I have gained initial professional experience; I have seen that many areas currently dominated by C and custom assembly code are likely to be replaced by Rust.
Cython is also a lower-level language by default, but unlike general-purpose languages like C and Rust, Cython is primarily used to write CPython extension modules. Cython is designed as a superset of Python, allowing programmers to choose when to support pure Python syntax, while Cython’s syntax extensions enable it to generate code that is comparable in speed and memory efficiency to native C code.
Learning one of these languages enhances one’s understanding of memory management, algorithm efficiency, binary interface compatibility, software portability, and the profound understanding of how source code is transformed into running systems.
Object-Oriented Data Modeling: Java, C#, Eiffel
One of the main tasks in programming is to model the state of the real world, and the most common approach is through the native syntactical support provided by object-oriented languages: combining data structures and methods that operate on those data structures into classes.
Python is designed to natively use object-oriented features without requiring one to learn how to write their own classes first. Not every language has this approach – for the languages listed in this section, learning object-oriented design principles is a prerequisite for using these languages.
Thanks to Sun Microsystems’ marketing of the Java language in the late 1990s, Java became the default language for many introductory computer science courses in colleges. Although it is now being replaced by Python in many educational fields, it remains one of the most popular languages in business application development. There are a number of other languages targeting the common JVM (Java Virtual Machine) runtime, including Python’s Jython implementation. The Android system’s Dalvik and ART environments are built on the Java programming API.
C# is similar to Java in many ways and emerged as a replacement for J++ (Microsoft’s implementation of Java) after Sun and Microsoft failed to resolve inconsistencies between J++ and standard Java. Like Java, it is also a popular language for commercial application development, with a number of other languages targeting the shared .NET CLR (Common Language Runtime) implementation, including Python’s IronPython implementation (the core components from the original IronPython 1.0 were extracted to create the intermediate layer for the .NET Dynamic Language Runtime). For a long time, .NET was a proprietary technology that could only be used on Windows systems, but in early 2015, Microsoft announced the .NET open-source initiative.
Unlike most languages on the list, I do not recommend using Eiffel in daily practice. It is included in the recommendation list because it has a wealth of excellent object-oriented design principles, including designing programs with the goal of being “correct and reliable”. (At the same time, Eiffel also tells me that for most software development, “correct and reliable” is not the design goal because correct and reliable software cannot adequately handle uncertain situations. This design philosophy is entirely unsuitable when many related constraints are still unclear and need to be gradually refined during iterative processes.)
Learning this type of programming language requires familiarity with inheritance models, contract design, class invariants, preconditions, postconditions, covariance, contravariance, method lookup paths, generic programming, and various other features supported by Python’s type system. Additionally, many standard library modules and third-party frameworks utilize “explicitly object-oriented” design styles, such as unittest and logging modules, as well as class-based views in the Django framework.
Object-Oriented C: C++, D
One way to use CPython is to treat its core as a programming environment that is a “C language with objects” – CPython implements object-oriented programming through the C language style by describing data with C structures and passing pointers to instances of those structures as the first argument to data processing functions (which is the omnipresent PyObject* pointer in C). This design pattern is intentionally replicated in Python, where instance methods and class methods need to explicitly specify self or cls as parameters.
C++ aims for source-level compatibility with C while adding some advanced features, such as native support for object-oriented programming and template-based metaprogramming. The obscurity and complexity of C++ are notorious (even though the updates to the language standard in 2011 resolved many of the worst issues), but C++ remains a choice in many scenarios, including 3D modeling graphics engines and cross-platform application development frameworks like Qt.
The D programming language is also interesting because its relationship with C++ is similar to that of Rust with C: the purpose of designing D is to retain most of C++’s advantages while avoiding many of its pitfalls (such as lack of memory safety). Unlike Rust, D is not a completely new programming language designed from scratch; rather, it is directly derived from C++. Although it is not a strict superset of C like C++, it adheres to a design principle that any code that falls within the common subset of C and D must behave the same in both languages.
Learning these languages is beneficial for deeply understanding the complexity of combining high-level language features with the low-level C runtime model. Learning C++ also helps when using Python to operate existing libraries and toolkits written in C++.
Array-Oriented Data Processing: MATLAB/Octave, Julia
Array-oriented programming is used for numerical programming models based on matrix algebra and related numerical methods.
Although Python’s standard library does not directly support this, it has been designed with a series of syntactical and semantical capabilities that facilitate third-party libraries like NumPy and similar array-oriented tools.
In many cases, Python’s scientific computing software suite is seen as a replacement for the dedicated MATLAB programming environment, widely used for modeling, simulation, and numerical analysis in science and engineering. The open-source project GNU Octave aims to be syntactically compatible with MATLAB code, allowing comparisons between these two object-oriented programming approaches.
Julia is another relatively new language, characterized by its support for array-oriented programming and type-based function overloading.
Learning one of these languages helps deepen the understanding of the power of Python’s scientific computing toolkits, while also studying how to leverage hardware-level concurrent execution using technologies like OpenCL and Nvidia’s CUDA, as well as exploring distributed data processing frameworks like Apache Spark and Blaze.
Statistical Data Analysis Language: R
With the increasing volume of big data sets that need processing, there is a need for a free analytical tool capable of handling such data sets, and the programming language R serves as such a tool, particularly focusing on statistical data analysis and visualization.
Learning R helps deepen the understanding of the statistical capabilities of Python’s scientific computing toolkits, especially within data analysis libraries like pandas and statistical visualization libraries like seaborn.
Computational Pipeline Modeling Languages: Haskell, Scala, Clojure, F#
Object-oriented data modeling and array-oriented data modeling primarily focus on static data modeling. There are two modeling approaches: one stores data in the various attributes of objects, while the other saves structured data as arrays.
In contrast, functional programming languages emphasize dynamic modeling of data in the form of computational flows. Learning the basics of functional programming significantly enhances one’s ability to model data using data transformation operations, which is also helpful when developing applications with other paradigms of programming languages (such as procedural, object-oriented, and array-oriented programming languages).
Haskell is a functional programming language that has had a significant impact on the design of Python, most notably with the introduction of list comprehensions in Python 2.0.
Scala is undoubtedly a functional programming language based on the JVM, and along with Java, Python, and R, it is one of the four main programming languages of the Apache Spark data analysis platform. While supporting functional programming styles, Scala’s syntax, data model, and execution model are designed to avoid imposing too much of a burden on existing Java programmers (from this perspective, Scala is better classified as an object-oriented programming language with strong functional language support).
Clojure is another functional programming language based on the JVM, regarded as a variant of Lisp. It earns a place on our list because it inspired the implementation of Python’s functional programming toolbox toolz.
I am not familiar with F#, but since it is a recommended language for .NET CLR, it is worth paying attention to.
Learning these programming languages helps understand Python’s own computational pipeline modeling tools, including container inference expressions, generators, generator expressions, functools, and itertools standard library modules, as well as third-party functional Python tools like toolz.
Event-Driven Programming Languages: JavaScript, Go, Erlang, Elixir
Computational pipelines are a great way to address data transformation and analysis problems, but many issues require programs to run persistently, waiting for events to occur and then processing those events. For such services, it is often possible to concurrently handle multiple events to serve multiple users (or at least multiple actions).
JavaScript was originally developed as an event-handling programming language for browsers, allowing web developers to handle local user actions (like mouse movements and key presses) and events (like page rendering completion). All modern browsers support JavaScript, which, together with HTML5’s DOM, has become the de facto standard for the appearance and behavior of user interfaces.
Go was designed by Google with the purpose of creating highly scalable network services. Go is very suitable for developing command-line programs. From the perspective of language design, the most notable aspect is that Go employs the concept of “Communicating Sequential Processes” in its core concurrency model.
Erlang was designed by Ericsson to manufacture highly reliable telephone switches and similar devices, and the well-known open-source framework RabbitMQ’s message server is implemented in Erlang. Erlang uses the Actor model to implement core concurrency primitives, disallowing direct data sharing between different threads; communication between threads can only occur through message passing. Although I have never used Erlang, my first job involved a concurrent framework developed based on the Actor model, which was created by a former Ericsson engineer using C++. I have also developed such frameworks based on TSK (tasks) and MBX (mailboxes) primitives, implemented in Texas Instruments’ lightweight DSP/BIOS runtime (now known as TI-TROS).
Elixir earns a place on this list because, while it runs on the Erlang virtual machine and shares the same concurrency semantics as the Erlang programming language, it also includes a series of additional language-level features, providing a more comprehensive development environment that is more inviting for developers transitioning from other programming languages (like Python, Java, or Ruby).
Learning such a language helps deepen the understanding of how Python itself supports concurrency and parallelism, including native coroutines, generator-based coroutines, the concurrent.futures and asyncio standard library modules, third-party network service development frameworks (like Twisted and Tornado), the newly introduced channels concept in Django, and event handling loops in GUI frameworks.
Mixed Static and Dynamic Typing: TypeScript
One of the most controversial features introduced in Python 3.5 is the new type module, which adds support for mixed typing to the Python ecosystem.
For developers who have encountered static typing programming languages primarily like C, C++, and Java, this can be a daunting idea.
Microsoft’s TypeScript provides mixed static and dynamic typing support for JavaScript applications, allowing you to have a more favorable view of this concept. TypeScript code compiles to JavaScript code (with no runtime type checking included in the compiled output), and TypeScript annotations for mainstream JavaScript libraries can be found in the DefinitelyTyped code repository.
As Chris Neugebauer pointed out in a presentation at Australia’s PyCon, this is quite similar to the relationship between Python and the type hinting library typeshed and type inference and analysis tools like mypy.
Essentially, both TypeScript and Python’s type hints serve as means to implement specific testing programs, whether as separate files (regular testing programs) or embedded within the main code (similar to type declarations in static programming languages). In either case, you can run separate commands to check if the remaining code adheres to known type constraints (for JavaScript and TypeScript, this is implicitly done at compile time; for Python’s type hints, it is an optional static analysis task).
Dynamic Metaprogramming: Hy, Ruby
A somewhat unsettling feature brought to Python by programming languages such as C, C++, C#, and Java is “code as data”: functions and classes can be runtime objects manipulated by other objects.
Hy is a variant of Lisp that can run on the CPython and PyPy virtual machines. Lisp excels at “code as data”; Lisp code itself consists of nested lists that describe the operations to be performed (the name of the language comes from “LISt Processor”). Lisp-style languages are powerful because they can easily implement their own domain-specific languages (DSLs), but this can sometimes make reading other people’s code challenging.
Ruby is similar to Python in many ways, but as a more open community, Ruby embraces dynamic metaprogramming more, while Python only “supports but does not encourage” this aspect. Features in this area include redefining classes to add methods and using closures to implement core language structures like iterators.
Learning these languages can deepen your understanding of Python’s own support for dynamic metaprogramming, including function and class decorators, monkey patching (dynamically modifying code), the unittest.mock standard library module, and third-party object proxy modules like wrapt (I have yet to find any programming language that helps understand Python’s metaclasses; if anyone has good suggestions, please let me know in the comments. Advanced features of metaclasses include core types, abstract base classes, enumeration types, and runtime execution of mixed type (dynamic and static type) expressions).
Pragmatists: Lua, PHP, Perl
Popular programming languages are usually not isolated – they belong to a large ecosystem (both commercial and community), along with end-users, framework developers, tool developers, educators, and more.
Lua is a popular programming language primarily embedded within large programs as a scripting engine. Notable examples include plugins written for the Warcraft game client, and the RPM tool that exists in many Linux distributions also incorporates Ruby. Compared to CPython, Lua’s runtime size is only one-tenth of its size, and its weaker introspection capabilities allow it to be more easily decoupled from other parts of the application and the host operating system. One noteworthy contribution from the Lua community to the Python ecosystem is that CPython and PyPy adopted LuaJIT FFI (Foreign Function Interface) as the basis for their JIT-friendly cffi interface library.
PHP is another popular programming language, widely used by early virtual server hosting providers due to its proficiency in generating HTML pages, and it is well-known as part of the LAMP stack (Linux-Apache-MySQL-PHP). Despite many frustrating conceptual flaws in its design, PHP has become the foundation for many well-known open-source web services, including the Drupal content management system, WordPress blogging engine, and the MediaWiki engine that powers Wikipedia. PHP also supports many important services, such as the distributed event reporting platform Ushahidi used by crowdsourcing communities.
Like PHP, Perl is a popular language on Linux systems. Unlike PHP, Perl is not known as a web development platform; its more common use is as a tool for system administrators to manage systems, handling strings with regular expressions and processing outputs from text-based Linux operating system commands. You can accomplish all tasks with Perl without needing to resort to tools like Whensh, awk, and sed.
Learning one of these languages does not provide any good insights into aesthetically pleasing or conceptually elegant programming language design. The possible outcome is to provide some structural knowledge and adoption knowledge about programming languages in practice, as well as understanding the role of serendipity, historical accumulation, and lowering entry barriers (by redistributing to make defaults possible), which are all stronger than the inherent capabilities of the language itself.
In particular, it can provide insights into the significance of projects like CKAN, OpenStack NFV, Blender, SciPy, OpenMDAO, PyGMO, PyCUDA, and the Raspberry Pi Foundation, ensuring that institutional investments in the Python ecosystem continue through extensive commercial organizations.
Numerical Computing Concepts: Scratch, Logo
Lastly, I often find myself caught in discussions between advocates of structured programming and object-oriented programming. The latter claims that object-oriented programming languages are as easy to learn as structured programming languages.
When we talk about teaching through specific numerical experiments (robotics), the models of subjects in simulation software have direct real-world counterparts; for example, students can interact with sensors, engines, relays, etc. I believe supporters of object-oriented programming have a point.
However, for others, I encounter a typical challenge: take a cookbook and convert one of the recipes into what you believe is an easy-to-learn object-oriented programming language, and then find a student who understands that programming language to continue converting the recipe along my lines. (I look forward to seeing academic researchers truly practice such a learning process – I would sincerely feel gratified by such a situation.) Most of the time, supporters do not have to follow such a process – merely conducting thought experiments in their minds is sufficient for them to feel how much preparatory knowledge is required to learn this “easy-to-learn” programming language.
However, another way to solve this problem is to learn those programming languages designed for teaching numerical computation to children.
One of the most popular is Scratch, which allows students to manipulate a closed graphical environment by dragging, enabling them to see the corresponding movements and reactions in the graphical interface. Graphical environments like Scratch are a programming approach similar to using comic strips to help children gradually learn to read and write.
However, the idea of using a specially designed educational programming language to manipulate a graphical interface is not new; one of the earliest classic environments, the Logo environment, was created in the 1960s (similar to Python’s own turtle module). At that time, the main thing you interacted with was a “turtle” that you could command to move and draw lines, thus altering the graphical environment. In this way, concepts like command lines, iteration, and state (e.g., drawing up, drawing down) are introduced based on people’s natural intuitive thinking (imagine if you were a turtle, what would happen if you turned 90 degrees to the right?).
Returning to the essence, as an experienced programmer, relearning any of the above programming languages is the most effective way to forget what has been learned (discarding some wheels): the concepts covered by these language tools help us recall those concepts we once took for granted but need to be relearned with a beginner’s perspective. When we do this, we are more willing to recall the entire logical chain, including those thinking steps we previously thought were self-evident and omitted, allowing us to work more effectively with students and other beginners.
-
The content is organized and published by Script Home. If there are any issues regarding the content, copyright, or others, please contact us, and we will delete the content at the first opportunity!
Long press the image below
Scan the QR code to follow Script Home