I know Ruby very well. I believe that I may need to learn Python presently. For those who know both, what concepts are similar between the two, and what are different?
I’m looking for a list similar to a primer I wrote for Learning Lua for JavaScripters: simple things like whitespace significance and looping constructs; the name of nil in Python, and what values are considered “truthy”; is it idiomatic to use the equivalent of map and each, or are mumblesomethingaboutlistcomprehensionsmumble the norm?
If I get a good variety of answers I’m happy to aggregate them into a community wiki. Or else you all can fight and crib from each other to try to create the one true comprehensive list.
Edit: To be clear, my goal is “proper” and idiomatic Python. If there is a Python equivalent of inject, but nobody uses it because there is a better/different way to achieve the common functionality of iterating a list and accumulating a result along the way, I want to know how you do things. Perhaps I’ll update this question with a list of common goals, how you achieve them in Ruby, and ask what the equivalent is in Python.
Python has functions; Ruby does not. In Python, you can take any function or method and pass it to another function. In Ruby, everything is a method, and methods can’t be directly passed. Instead, you have to wrap them in Proc’s to pass them.
Ruby and Python both support closures, but in different ways. In Python, you can define a function inside another function. The inner function has read access to variables from the outer function, but not write access. In Ruby, you define closures using blocks. The closures have full read and write access to variables from the outer scope.
Python has list comprehensions, which are pretty expressive. For example, if you have a list of numbers, you can write
[x*x for x in values if x > 15]
to get a new list of the squares of all values greater than 15. In Ruby, you’d have to write the following:
values.select {|v| v > 15}.map {|v| v * v}
The Ruby code doesn’t feel as compact. It’s also not as efficient since it first converts the values array into a shorter intermediate array containing the values greater than 15. Then, it takes the intermediate array and generates a final array containing the squares of the intermediates. The intermediate array is then thrown out. So, Ruby ends up with 3 arrays in memory during the computation; Python only needs the input list and the resulting list.
Python also supplies similar map comprehensions.
Python supports tuples; Ruby doesn’t. In Ruby, you have to use arrays to simulate tuples.
Ruby supports switch/case statements; Python does not.
Ruby supports the standard expr ? val1 : val2 ternary operator; Python does not.
Ruby supports only single inheritance. If you need to mimic multiple inheritance, you can define modules and use mix-ins to pull the module methods into classes. Python supports multiple inheritance rather than module mix-ins.
Python supports only single-line lambda functions. Ruby blocks, which are kind of/sort of lambda functions, can be arbitrarily big. Because of this, Ruby code is typically written in a more functional style than Python code. For example, to loop over a list in Ruby, you typically do
collection.each do |value|
...
end
The block works very much like a function being passed to collection.each. If you were to do the same thing in Python, you’d have to define a named inner function and then pass that to the collection each method (if list supported this method):
That doesn’t flow very nicely. So, typically the following non-functional approach would be used in Python:
for value in collection:
...
Using resources in a safe way is quite different between the two languages. Here, the problem is that you want to allocate some resource (open a file, obtain a database cursor, etc), perform some arbitrary operation on it, and then close it in a safe manner even if an exception occurs.
In Ruby, because blocks are so easy to use (see #9), you would typically code this pattern as a method that takes a block for the arbitrary operation to perform on the resource.
In Python, passing in a function for the arbitrary action is a little clunkier since you have to write a named, inner function (see #9). Instead, Python uses a with statement for safe resource handling. See How do I correctly clean up a Python object? for more details.
I’ve just spent a couple of months learning Python after 6 years of Ruby. There really was no great comparison out there for the two languages, so I decided to man up and write one myself. Now, it is mainly concerned with functional programming, but since you mention Ruby’s inject method, I’m guessing we’re on the same wavelength.
A couple of points that will get you moving in the right direction:
All the functional programming goodness you use in Ruby is in Python, and it’s even easier. For example, you can map over functions exactly as you’d expect:
Python doesn’t have a method that acts like each. Since you only use each for side effects, the equivalent in Python is the for loop:
for n in [1, 2, 3]:
print n
List comprehensions are great when a) you have to deal with functions and object collections together and b) when you need to iterate using multiple indexes. For example, to find all the palindromes in a string (assuming you have a function p() that returns true for palindromes), all you need is a single list comprehension:
s = 'string-with-palindromes-like-abbalabba'
l = len(s)
[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]
My suggestion: Don’t try to learn the differences. Learn how to approach the problem in Python. Just like there’s a Ruby approach to each problem (that works very well givin the limitations and strengths of the language), there’s a Python approach to the problem. they are both different. To get the best out of each language, you really should learn the language itself, and not just the “translation” from one to the other.
Now, with that said, the difference will help you adapt faster and make 1 off modifications to a Python program. And that’s fine for a start to get writing. But try to learn from other projects the why behind the architecture and design decisions rather than the how behind the semantics of the language…
回答 3
我几乎不了解Ruby,但是这里有一些关于您提到的内容的要点:
nil,表示缺少值的值将是None(请注意,您可以像x is None或那样检查它x is not None,而不用==-或通过强制布尔值检查它,请参阅下一点)。
I know little Ruby, but here are a few bullet points about the things you mentioned:
nil, the value indicating lack of a value, would be None (note that you check for it like x is None or x is not None, not with == – or by coercion to boolean, see next point).
None, zero-esque numbers (0, 0.0, 0j (complex number)) and empty collections ([], {}, set(), the empty string "", etc.) are considered falsy, everything else is considered truthy.
For side effects, (for-)loop explicitly. For generating a new bunch of stuff without side-effects, use list comprehensions (or their relatives – generator expressions for lazy one-time iterators, dict/set comprehensions for the said collections).
Concerning looping: You have for, which operates on an iterable(! no counting), and while, which does what you would expect. The fromer is far more powerful, thanks to the extensive support for iterators. Not only nearly everything that can be an iterator instead of a list is an iterator (at least in Python 3 – in Python 2, you have both and the default is a list, sadly). The are numerous tools for working with iterators – zip iterates any number of iterables in parallel, enumerate gives you (index, item) (on any iterable, not just on lists), even slicing abritary (possibly large or infinite) iterables! I found that these make many many looping tasks much simpler. Needless to say, they integrate just fine with list comprehensions, generator expressions, etc.
In Ruby, instance variables and methods are completely unrelated, except when you explicitly relate them with attr_accessor or something like that.
In Python, methods are just a special class of attribute: one that is executable.
So for example:
>>> class foo:
... x = 5
... def y(): pass
...
>>> f = foo()
>>> type(f.x)
<type 'int'>
>>> type(f.y)
<type 'instancemethod'>
That difference has a lot of implications, like for example that referring to f.x refers to the method object, rather than calling it. Also, as you can see, f.x is public by default, whereas in Ruby, instance variables are private by default.
I am new to Ruby. I’m looking to import functions from a module that contains a tool I want to continue using separately. In Python I would simply do this:
From the Ruby I’ve seen out in the wild (granted, not a ton), this is not a standard Ruby design pattern. Modules and scripts are supposed to stay separate, so I wouldn’t be surprised if there isn’t really a good, clean way of doing this.
If stack trace is empty, we can start executing to the right and left. I don’t know if that’s used conventionally or unconventionally since I’m into Ruby for about a week.
if caller.length == 0
# do stuff
end
Proof of concept:
file: test.rb
#!/usr/bin/ruby
if caller.length == 0
puts "Main script"
end
puts "Test"
$ virtualenv test
New python executable in test/bin/python
Installing setuptools...cd .........done.
$ cd test/
$ source bin/activate
(test)$ easy_install tvnamer
Searchingfor tvnamer
Best match: tvnamer 0.5.1Processing tvnamer-0.5.1-py2.5.eggAdding tvnamer 0.5.1 to easy-install.pth file
Installing tvnamer script to /Users/dbr/test/bin
Using/Library/Python/2.5/site-packages/tvnamer-0.5.1-py2.5.eggProcessing dependencies for tvnamer
Finished processing dependencies for tvnamer
(test)$ which tvnamer
/Users/dbr/test/bin/tvnamer
Is there something similar to the Python utility virtualenv?
Basically it allows you to install Python packages into a sandboxed environment, so easy_install django doesn’t go in your system-wide site-packages directory, it would go in the virtualenv-created directory.
For example:
$ virtualenv test
New python executable in test/bin/python
Installing setuptools...cd .........done.
$ cd test/
$ source bin/activate
(test)$ easy_install tvnamer
Searching for tvnamer
Best match: tvnamer 0.5.1
Processing tvnamer-0.5.1-py2.5.egg
Adding tvnamer 0.5.1 to easy-install.pth file
Installing tvnamer script to /Users/dbr/test/bin
Using /Library/Python/2.5/site-packages/tvnamer-0.5.1-py2.5.egg
Processing dependencies for tvnamer
Finished processing dependencies for tvnamer
(test)$ which tvnamer
/Users/dbr/test/bin/tvnamer
I’ll mention the way I do this with Bundler (which I use with RVM – RVM to manage the rubies and a default set of global gems, Bundler to handle project specific gems)
bundler install --binstubs --path vendor
Running this command in the root of a project will install the gems listed from your Gemfile, put the libs in ./vendor, and any executables in ./bin and all requires (if you use bundle console or the Bundler requires) will reference these exes and libs.
I recommend direnv. It is an environment switcher for the shell.
Before each prompt it checks for the existence of an “.envrc” file in the current and parent directories. If the file exists (and authorized), it is loaded into a bash sub-shell and all exported variables are then captured by direnv and then made available the current shell.
This will put all gems under the project’s .direnv/ruby directory (makes opening gems easier). bundler will put wrapper binaries in .direnv/bin (no more bundle exec!).
+ rbenv
It’s also possible to use rbenv by adding the use rbenv command in any .envrc file. This will activate rbenv which in turn will put the ruby wrappers in the PATH.
Note that it’s not necessary to install rbenv in the .bashrc or .zshrc for this to work.
+ RVM
Here is the most complicated .envrc that I use on ruby projects:
rvm use 1.8.7
layout ruby
PATH_add .direnv/bundler-bin
rvm is used to select the right ruby version for you
layout commands automatically set some of the usual environment variables. For now only the ruby layout exists. What it does is set the GEM_HOME environment variable and it’s bin directory to your path. Because it depends on the ruby version, make sure to call it after “rvm”. Since each ruby layout directories have their own GEM_HOME, you don’t need to use rvm’s gemsets.
PATH_add prepends and expands the given relative path. In that case, I use this to segregate the bundler binstubs from my own bin scripts with bundle install --binstubs .direnv/bundler-bin
If you want to find out what those commands exactly do, for now: cat direnv stdlib | less
def frobnicate(bar):"""frobnicate takes a bar and frobnicates it
>>> bar = Bar()
>>> bar.is_frobnicated()
False
>>> frobnicate(bar)
>>> bar.is_frobnicated()
True
"""
There is a lot of discussions of Python vs Ruby, and I all find them completely unhelpful, because they all turn around why feature X sucks in language Y, or that claim language Y doesn’t have X, although in fact it does. I also know exactly why I prefer Python, but that’s also subjective, and wouldn’t help anybody choosing, as they might not have the same tastes in development as I do.
It would therefore be interesting to list the differences, objectively. So no “Python’s lambdas sucks”. Instead explain what Ruby’s lambdas can do that Python’s can’t. No subjectivity. Example code is good!
Don’t have several differences in one answer, please. And vote up the ones you know are correct, and down those you know are incorrect (or are subjective). Also, differences in syntax is not interesting. We know Python does with indentation what Ruby does with brackets and ends, and that @ is called self in Python.
UPDATE: This is now a community wiki, so we can add the big differences here.
Ruby has a class reference in the class body
In Ruby you have a reference to the class (self) already in the class body. In Python you don’t have a reference to the class until after the class construction is finished.
An example:
class Kaka
puts self
end
self in this case is the class, and this code would print out “Kaka”. There is no way to print out the class name or in other ways access the class from the class definition body in Python (outside method definitions).
All classes are mutable in Ruby
This lets you develop extensions to core classes. Here’s an example of a rails extension:
class String
def starts_with?(other)
head = self[0, other.length]
head == other
end
end
Python (imagine there were no ''.startswith method):
You could use it on any sequence (not just strings). In order to use it you should import it explicitly e.g., from some_module import starts_with.
Ruby has Perl-like scripting features
Ruby has first class regexps, $-variables, the awk/perl line by line input loop and other features that make it more suited to writing small shell scripts that munge text files or act as glue code for other programs.
Ruby has first class continuations
Thanks to the callcc statement. In Python you can create continuations by various techniques, but there is no support built in to the language.
Ruby has blocks
With the “do” statement you can create a multi-line anonymous function in Ruby, which will be passed in as an argument into the method in front of do, and called from there. In Python you would instead do this either by passing a method or with generators.
Ruby:
amethod { |here|
many=lines+of+code
goes(here)
}
Python (Ruby blocks correspond to different constructs in Python):
with amethod() as here: # `amethod() is a context manager
many=lines+of+code
goes(here)
Or
for here in amethod(): # `amethod()` is an iterable
many=lines+of+code
goes(here)
Or
def function(here):
many=lines+of+code
goes(here)
amethod(function) # `function` is a callback
Interestingly, the convenience statement in Ruby for calling a block is called “yield”, which in Python will create a generator.
Ruby:
def themethod
yield 5
end
themethod do |foo|
puts foo
end
Python:
def themethod():
yield 5
for foo in themethod():
print foo
Although the principles are different, the result is strikingly similar.
Ruby supports functional style (pipe-like) programming more easily
descriptions = (f.description() for f in mylist)
"\n".join(filter(len, descriptions))
Python has built-in generators (which are used like Ruby blocks, as noted above)
Python has support for generators in the language. In Ruby 1.8 you can use the generator module which uses continuations to create a generator from a block. Or, you could just use a block/proc/lambda! Moreover, in Ruby 1.9 Fibers are, and can be used as, generators, and the Enumerator class is a built-in generator 4
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
Contrast this with the above block examples.
Python has flexible name space handling
In Ruby, when you import a file with require, all the things defined in that file will end up in your global namespace. This causes namespace pollution. The solution to that is Rubys modules. But if you create a namespace with a module, then you have to use that namespace to access the contained classes.
In Python, the file is a module, and you can import its contained names with from themodule import *, thereby polluting the namespace if you want. But you can also import just selected names with from themodule import aname, another or you can simply import themodule and then access the names with themodule.aname. If you want more levels in your namespace you can have packages, which are directories with modules and an __init__.py file.
Python has docstrings
Docstrings are strings that are attached to modules, functions and methods and can be
introspected at runtime. This helps for creating such things as the help command and
automatic documentation.
def frobnicate(bar):
"""frobnicate takes a bar and frobnicates it
>>> bar = Bar()
>>> bar.is_frobnicated()
False
>>> frobnicate(bar)
>>> bar.is_frobnicated()
True
"""
Ruby’s equivalent are similar to javadocs, and located above the method instead of within it. They can be retrieved at runtime from the files by using 1.9’s Method#source_location example use
Python has multiple inheritance
Ruby does not (“on purpose” — see Ruby’s website, see here how it’s done in Ruby). It does reuse the module concept as a type of abstract classes.
Python has list/dict comprehensions
Python:
res = [x*x for x in range(1, 10)]
Ruby:
res = (0..9).map { |x| x * x }
Python:
>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7c1ccd4>
>>> list(_)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Ruby:
p = proc { |x| x * x }
(0..9).map(&p)
Python 2.7+:
>>> {x:str(y*y) for x,y in {1:2, 3:4}.items()}
{1: '4', 3: '16'}
Things similar to decorators can also be created in Ruby, and it can also be argued that they aren’t as necessary as in Python.
Syntax differences
Ruby requires “end” or “}” to close all of its scopes, while Python uses white-space only. There have been recent attempts in Ruby to allow for whitespace only indentation http://github.com/michaeledgar/seamless
Ruby has the concepts of blocks, which are essentially syntactic sugar around a section of code; they are a way to create closures and pass them to another method which may or may not use the block. A block can be invoked later on through a yield statement.
For example, a simple definition of an each method on Array might be something like:
class Array
def each
for i in self
yield(i) # If a block has been passed, control will be passed here.
end
end
end
Then you can invoke this like so:
# Add five to each element.
[1, 2, 3, 4].each{ |e| puts e + 5 }
> [6, 7, 8, 9]
Python has anonymous functions/closures/lambdas, but it doesn’t quite have blocks since it’s missing some of the useful syntactic sugar. However, there’s at least one way to get it in an ad-hoc fashion. See, for example, here.
This is a fundamental feature of modern scripting languages. JavaScript and Lua do this, too. Ruby doesn’t treat functions this way; naming a function calls it.
Of course, there are ways to do these things in Ruby, but they’re not first-class operations. For example, you can wrap a function with Proc.new to treat it as a variable–but then it’s no longer a function; it’s an object with a “call” method.
Ruby’s functions aren’t first-class objects
Ruby functions aren’t first-class objects. Functions must be wrapped in an object to pass them around; the resulting object can’t be treated like a function. Functions can’t be assigned in a first-class manner; instead, a function in its container object must be called to modify them.
Ultimately all answers are going to be subjective at some level, and the answers posted so far pretty much prove that you can’t point to any one feature that isn’t doable in the other language in an equally nice (if not similar) way, since both languages are very concise and expressive.
I like Python’s syntax. However, you have to dig a bit deeper than syntax to find the true beauty of Ruby. There is zenlike beauty in Ruby’s consistency. While no trivial example can possibly explain this completely, I’ll try to come up with one here just to explain what I mean.
Reverse the words in this string:
sentence = "backwards is sentence This"
When you think about how you would do it, you’d do the following:
Split the sentence up into words
Reverse the words
Re-join the words back into a string
In Ruby, you’d do this:
sentence.split.reverse.join ' '
Exactly as you think about it, in the same sequence, one method call after another.
In python, it would look more like this:
" ".join(reversed(sentence.split()))
It’s not hard to understand, but it doesn’t quite have the same flow. The subject (sentence) is buried in the middle. The operations are a mix of functions and object methods. This is a trivial example, but one discovers many different examples when really working with and understanding Ruby, especially on non-trivial tasks.
Python has a “we’re all adults here” mentality. Thus, you’ll find that Ruby has things like constants while Python doesn’t (although Ruby’s constants only raise a warning). The Python way of thinking is that if you want to make something constant, you should put the variable names in all caps and not change it.
For example, Ruby:
>> PI = 3.14
=> 3.14
>> PI += 1
(irb):2: warning: already initialized constant PI
=> 4.14
Python:
>>> PI = 3.14
>>> PI += 1
>>> PI
4.1400000000000006
You can import only specific functions from a module in Python. In Ruby, you import the whole list of methods. You could “unimport” them in Ruby, but it’s not what it’s all about.
EDIT:
let’s take this Ruby module :
module Whatever
def method1
end
def method2
end
end
if you include it in your code :
include Whatever
you’ll see that both method1 and method2 have been added to your namespace. You can’t import only method1. You either import them both or you don’t import them at all. In Python you can import only the methods of your choosing. If this would have a name maybe it would be called selective importing?
You can read docs on the command line (with the ri command instead of pydoc).
There are no special line terminators (except the usual newline).
String literals can span multiple lines like Python’s triple-quoted strings.
Brackets are for lists, and braces are for dicts (which, in Ruby, are called “hashes”).
Arrays work the same (adding them makes one long array, but composing them like this a3 = [ a1, a2 ] gives you an array of arrays).
Objects are strongly and dynamically typed.
Everything is an object, and variables are just references to objects.
Although the keywords are a bit different, exceptions work about the same.
You’ve got embedded doc tools (Ruby’s is called rdoc).
Differences
Unlike Python, in Ruby,…
Strings are mutable.
You can make constants (variables whose value you don’t intend to change).
There are some enforced case-conventions (ex. class names start with a capital letter, variables start with a lowercase letter).
There’s only one kind of list container (an Array), and it’s mutable.
Double-quoted strings allow escape sequences (like \t) and a special “expression substitution” syntax (which allows you to insert the results of Ruby expressions directly into other strings without having to “add ” + “strings ” + “together”). Single-quoted strings are like Python’s r”raw strings”.
There are no “new style” and “old style” classes. Just one kind.
You never directly access attributes. With Ruby, it’s all method calls.
Parentheses for method calls are usually optional.
There’s public, private, and protected to enforce access, instead of Python’s _voluntary_ underscore __convention__.
“mixin’s” are used instead of multiple inheritance.
You can add or modify the methods of built-in classes. Both languages let you open up and modify classes at any point, but Python prevents modification of built-ins — Ruby does not.
You’ve got true and false instead of True and False (and nil instead of None).
When tested for truth, only false and nil evaluate to a false value. Everything else is true (including 0, 0.0, “”, and []).
It’s elsif instead of elif.
It’s require instead of import. Otherwise though, usage is the same.
The usual-style comments on the line(s) above things (instead of docstrings below them) are used for generating docs.
There are a number of shortcuts that, although give you more to remember, you quickly learn. They tend to make Ruby fun and very productive.
What Ruby has over Python are its scripting language capabilities. Scripting language in this context meaning to be used for “glue code” in shell scripts and general text manipulation.
These are mostly shared with Perl. First-class built-in regular expressions, $-Variables, useful command line options like Perl (-a, -e) etc.
Together with its terse yet epxressive syntax it is perfect for these kind of tasks.
Python to me is more of a dynamically typed business language that is very easy to learn and has a neat syntax. Not as “cool” as Ruby but neat.
What Python has over Ruby to me is the vast number of bindings for other libs. Bindings to Qt and other GUI libs, many game support libraries and and and. Ruby has much less. While much used bindings e.g. to Databases are of good quality I found niche libs to be better supported in Python even if for the same library there is also a Ruby binding.
So, I’d say both languages have its use and it is the task that defines which one to use. Both are easy enough to learn. I use them side-by-side. Ruby for scripting and Python for stand-alone apps.
I don’t think “Ruby has X and Python doesn’t, while Python has Y and Ruby doesn’t” is the most useful way to look at it. They’re quite similar languages, with many shared abilities.
To a large degree, the difference is what the language makes elegant and readable. To use an example you brought up, both do theoretically have lambdas, but Python programmers tend to avoid them, and constructs made using them do not look anywhere near as readable or idiomatic as in Ruby. So in Python, a good programmer will want to take a different route to solving the problem than he would in Ruby, just because it actually is the better way to do it.
I’d like to suggest a variant of the original question, “What does Ruby have that Python doesn’t, and vice versa?” which admits the disappointing answer, “Well, what can you do with either Ruby or Python that can’t be done in Intercal?” Nothing on that level, because Python and Ruby are both part of the vast royal family sitting on the throne of being Turing approximant.
But what about this:
What can be done gracefully and well in Python that can’t be done in Ruby with such beauty and good engineering, or vice versa?
That may be much more interesting than mere feature comparison.
Python has much better integration with C++ (via things like Boost.Python, SIP, and Py++) than Ruby, where the options seem to be either write directly against the Ruby interpreter API (which you can do with Python as well, of course, but in both cases doing so is low level, tedious, and error prone) or use SWIG (which, while it works and definitely is great if you want to support many languages, isn’t nearly as nice as Boost.Python or SIP if you are specifically looking to bind C++).
Python has a number of web application environments (Django, Pylons/Turbogears, web.py, probably at least half a dozen others), whereas Ruby (effectively) has one: Rails. (Other Ruby web frameworks do exist, but seemingly have a hard time getting much traction against Rails). Is this aspect good or bad? Hard to say, and probably quite subjective; I can easily imagine arguments that the Python situation is better and that the Ruby situation is better.
Culturally, the Python and Ruby communities seem somewhat different, but I can only hint at this as I don’t have that much experience interacting with the Ruby community. I’m adding this mostly in the hopes that someone who has a lot of experience with both can amplify (or reject) this statement.
当然,在Ruby中,我确实会在每个块的末尾键入愚蠢的“ end”(而不是不缩进)而感到疲倦-但是,我确实避免输入Python要求的同样愚蠢的’:’。每个块的
开始,所以几乎可以洗了:-)。其他语法差异,例如’@foo’与’self.foo’,或者Ruby vs Python中case的较高重要性,实际上与我无关。
What’s better about Ruby than Python? I’m sure there’s something.
What is it?
Wouldn’t it make much more sense to ask Ruby people this, rather than
Python people?
Might, or might not, depending on
one’s purposes — for example, if
one’s purposes include a “sociological
study” of the Python community, then
putting questions to that community is
likely to prove more revealing of
information about it, than putting
them elsewhere:-).
Personally, I gladly took the
opportunity to follow Dave Thomas’
one-day Ruby tutorial at last OSCON.
Below a thin veneer of syntax
differences, I find Ruby and Python
amazingly similar — if I was
computing the minimum spanning tree
among just about any set of languages,
I’m pretty sure Python and Ruby would
be the first two leaves to coalesce
into an intermediate node:-).
Sure, I do get weary, in Ruby, of
typing the silly “end” at the end of
each block (rather than just
unindenting) — but then I do get to
avoid typing the equally-silly ‘:’
which Python requires at the
start of each block, so that’s almost a wash:-). Other syntax
differences such as ‘@foo’ versus
‘self.foo’, or the higher significance
of case in Ruby vs Python, are really
just about as irrelevant to me.
Others no doubt base their choice of
programming languages on just such
issues, and they generate the hottest
debates — but to me that’s just an
example of one of Parkinson’s Laws in
action (the amount on debate on an
issue is inversely proportional to the
issue’s actual importance).
Edit (by AM 6/19/2010 11:45): this is also known as “painting the
bikeshed” (or, for short,
“bikeshedding”) — the reference is,
again, to Northcote Parkinson, who
gave “debates on what color to paint
the bikeshed” as a typical example of
“hot debates on trivial topics”.
(end-of-Edit).
One syntax difference that I do find
important, and in Python’s favor —
but other people will no doubt think
just the reverse — is “how do you
call a function which takes no
parameters”. In Python (like in C),
to call a function you always apply
the “call operator” — trailing
parentheses just after the object
you’re calling (inside those trailing
parentheses go the args you’re passing
in the call — if you’re passing no
args, then the parentheses are empty).
This leaves the mere mention of
any object, with no operator involved, as meaning just a reference
to the object — in any context,
without special cases, exceptions,
ad-hoc rules, and the like. In Ruby
(like in Pascal), to call a function
WITH arguments you pass the args
(normally in parentheses, though that
is not invariably the case) — BUT if
the function takes no args then simply
mentioning the function implicitly
calls it. This may meet the
expectations of many people (at least,
no doubt, those whose only previous
experience of programming was with
Pascal, or other languages with
similar “implicit calling”, such as
Visual Basic) — but to me, it means
the mere mention of an object may
EITHER mean a reference to the object,
OR a call to the object, depending on
the object’s type — and in those
cases where I can’t get a reference to
the object by merely mentioning it I
will need to use explicit “give me a
reference to this, DON’T call it!”
operators that aren’t needed
otherwise. I feel this impacts the
“first-classness” of functions (or
methods, or other callable objects)
and the possibility of interchanging
objects smoothly. Therefore, to me,
this specific syntax difference is a
serious black mark against Ruby — but
I do understand why others would thing
otherwise, even though I could hardly
disagree more vehemently with them:-).
Below the syntax, we get into some
important differences in elementary
semantics — for example, strings in
Ruby are mutable objects (like in
C++), while in Python they are not
mutable (like in Java, or I believe
C#). Again, people who judge
primarily by what they’re already
familiar with may think this is a plus
for Ruby (unless they’re familiar with
Java or C#, of course:-). Me, I think
immutable strings are an excellent
idea (and I’m not surprised that Java,
independently I think, reinvented that
idea which was already in Python),
though I wouldn’t mind having a
“mutable string buffer” type as well
(and ideally one with better
ease-of-use than Java’s own “string
buffers”); and I don’t give this
judgment because of familiarity —
before studying Java, apart from
functional programming languages where
all data are immutable, all the languages I knew had mutable strings
— yet when I first saw the immutable-string idea in Java (which I
learned well before I learned Python),
it immediately struck me as excellent,
a very good fit for the
reference-semantics of a higher level
programming language (as opposed to
the value-semantics that fit best with
languages closer to the machine and
farther from applications, such as C)
with strings as a first-class,
built-in (and pretty crucial) data
type.
Ruby does have some advantages in
elementary semantics — for example,
the removal of Python’s “lists vs
tuples” exceedingly subtle
distinction. But mostly the score (as
I keep it, with simplicity a big plus
and subtle, clever distinctions a
notable minus) is against Ruby (e.g.,
having both closed and half-open
intervals, with the notations a..b and
a…b [anybody wants to claim that
it’s obvious which is which?-)], is
silly — IMHO, of course!). Again,
people who consider having a lot of
similar but subtly different things at
the core of a language a PLUS, rather
than a MINUS, will of course count
these “the other way around” from how
I count them:-).
Don’t be misled by these comparisons
into thinking the two languages are
very different, mind you. They aren’t. But if I’m asked to compare
“capelli d’angelo” to “spaghettini”,
after pointing out that these two
kinds of pasta are just about
undistinguishable to anybody and
interchangeable in any dish you might
want to prepare, I would then
inevitably have to move into
microscopic examination of how the
lengths and diameters imperceptibly
differ, how the ends of the strands
are tapered in one case and not in the
other, and so on — to try and explain
why I, personally, would rather have
capelli d’angelo as the pasta in any
kind of broth, but would prefer
spaghettini as the pastasciutta to go
with suitable sauces for such long
thin pasta forms (olive oil, minced
garlic, minced red peppers, and finely
ground anchovies, for example – but if
you sliced the garlic and peppers
instead of mincing them, then you
should choose the sounder body of
spaghetti rather than the thinner
evanescence of spaghettini, and would
be well advised to forego the achovies
and add instead some fresh spring
basil [or even — I’m a heretic…! —
light mint…] leaves — at the very
last moment before serving the dish).
Ooops, sorry, it shows that I’m
traveling abroad and haven’t had pasta
for a while, I guess. But the analogy
is still pretty good!-)
So, back to Python and Ruby, we come
to the two biggies (in terms of
language proper — leaving the
libraries, and other important
ancillaries such as tools and
environments, how to embed/extend each
language, etc, etc, out of it for now
— they wouldn’t apply to all IMPLEMENTATIONS of each language
anyway, e.g., Jython vs Classic Python
being two implementations of the
Python language!):
Ruby’s iterators and codeblocks vs Python’s iterators and generators;
Ruby’s TOTAL, unbridled “dynamicity”, including the ability
to “reopen” any existing class,
including all built-in ones, and
change its behavior at run-time — vs
Python’s vast but bounded
dynamicity, which never changes the
behavior of existing built-in
classes and their instances.
Personally, I consider 1 a wash (the
differences are so deep that I could
easily see people hating either
approach and revering the other, but
on MY personal scales the pluses and
minuses just about even up); and 2 a
crucial issue — one that makes Ruby
much more suitable for “tinkering”,
BUT Python equally more suitable for
use in large production applications.
It’s funny, in a way, because both
languages are so MUCH more dynamic
than most others, that in the end the
key difference between them from my
POV should hinge on that — that Ruby
“goes to eleven” in this regard (the
reference here is to “Spinal Tap”, of
course). In Ruby, there are no limits
to my creativity — if I decide that
all string comparisons must become
case-insensitive, I CAN DO THAT!
I.e., I can dynamically alter the
built-in string class so that
a = “Hello World”
b = “hello world”
if a == b
print “equal!\n”
else
print “different!\n”
end WILL print “equal”. In python, there is NO way I can do that.
For the purposes of metaprogramming,
implementing experimental frameworks,
and the like, this amazing dynamic
ability of Ruby is extremely
appealing. BUT — if we’re talking
about large applications, developed by
many people and maintained by even
more, including all kinds of libraries
from diverse sources, and needing to
go into production in client sites…
well, I don’t WANT a language that is
QUITE so dynamic, thank you very much.
I loathe the very idea of some library
unwittingly breaking other unrelated
ones that rely on those strings being
different — that’s the kind of deep
and deeply hidden “channel”, between
pieces of code that LOOK separate and
SHOULD BE separate, that spells
d-e-a-t-h in large-scale programming.
By letting any module affect the
behavior of any other “covertly”, the
ability to mutate the semantics of
built-in types is just a BAD idea for
production application programming,
just as it’s cool for tinkering.
If I had to use Ruby for such a large
application, I would try to rely on
coding-style restrictions, lots of
tests (to be rerun whenever ANYTHING
changes — even what should be totally
unrelated…), and the like, to
prohibit use of this language feature.
But NOT having the feature in the
first place is even better, in my
opinion — just as Python itself would
be an even better language for
application programming if a certain
number of built-ins could be “nailed
down”, so I KNEW that, e.g.,
len(“ciao”) is 4 (rather than having
to worry subliminally about whether
somebody’s changed the binding of name
‘len’ in the builtins module…).
I do hope that eventually Python does
“nail down” its built-ins.
But the problem’s minor, since
rebinding built-ins is quite a
deprecated as well as a rare practice
in Python. In Ruby, it strikes me as
major — just like the too powerful
macro facilities of other languages
(such as, say, Dylan) present similar
risks in my own opinion (I do hope
that Python never gets such a powerful
macro system, no matter the allure of
“letting people define their own
domain-specific little languages
embedded in the language itself” — it
would, IMHO, impair Python’s wonderful
usefulness for application
programming, by presenting an
“attractive nuisance” to the would-be
tinkerer who lurks in every
programmer’s heart…).
I’m unsure of this, so I add it as an answer first.
Python treats unbound methods as functions
That means you can call a method either like theobject.themethod() or by TheClass.themethod(anobject).
Edit: Although the difference between methods and functions is small in Python, and non-existant in Python 3, it also doesn’t exist in Ruby, simply because Ruby doesn’t have functions. When you define functions, you are actually defining methods on Object.
But you still can’t take the method of one class and call it as a function, you would have to rebind it to the object you want to call on, which is much more obstuse.
I would like to mention Python descriptor API that allows one customize object-to-attribute “communication”. It is also noteworthy that, in Python, one is free to implement an alternative protocol via overriding the default given through the default implementation of the __getattribute__ method.
Let me give more details about the aforementioned.
Descriptors are regular classes with __get__, __set__ and/or __delete__ methods.
When interpreter encounters something like anObj.anAttr, the following is performed:
__getattribute__ method of anObj is invoked
__getattribute__ retrieves anAttr object from the class dict
it checks whether abAttr object has __get__, __set__ or __delete__ callable objects
the context (i.e., caller object or class, and value, instead of the latter, if we have setter) is passed to the callable object
the result is returned.
As was mentioned, this is the default behavior. One is free to change the protocol by re-implementing __getattribute__.
This technique is lot more powerful than decorators.
Python has docstrings and ruby doesn’t… Or if it doesn’t, they are not accessible as easily as in python.
Ps. If im wrong, pretty please, leave an example? I have a workaround that i could monkeypatch into classes quite easily but i’d like to have docstring kinda of a feature in “native way”.
Ruby has a line by line loop over input files (the ‘-n’ flag) from the commandline so it can be used like AWK. This Ruby one-liner:
ruby -ne 'END {puts $.}'
will count lines like the AWK one-liner:
awk 'END{print NR}'
Ruby gets feature this through Perl, which took it from AWK as a way of getting sysadmins on board with Perl without having to change the way they do things.
My python’s rusty, so some of these may be in python and i just don’t remember/never learned in the first place, but here are the first few that I thought of:
Whitespace
Ruby handles whitespace completely different. For starters, you don’t need to indent anything (which means it doesn’t matter if you use 4 spaces or 1 tab). It also does smart line continuation, so the following is valid:
def foo(bar,
cow)
Basically, if you end with an operator, it figures out what is going on.
Mixins
Ruby has mixins which can extend instances instead of full classes:
module Humor
def tickle
"hee, hee!"
end
end
a = "Grouchy"
a.extend Humor
a.tickle » "hee, hee!"
Enums
I’m not sure if this is the same as generators, but as of Ruby 1.9 ruby as enums, so
You can have code in the class definition in both Ruby and Python. However, in Ruby you have a reference to the class (self). In Python you don’t have a reference to the class, as the class isn’t defined yet.
An example:
class Kaka
puts self
end
self in this case is the class, and this code would print out “Kaka”. There is no way to print out the class name or in other ways access the class from the class definition body in Python.
Syntax is not a minor thing, it has a direct impact on how we think. It also has a direct effect on the rules we create for the systems we use. As an example we have the order of operations because of the way we write mathematical equations or sentences. The standard notation for mathematics allows people to read it more than one way and arrive at different answers given the same equation. If we had used prefix or postfix notation we would have created rules to distinguish what the numbers to be manipulated were rather than only having rules for the order in which to compute values.
The standard notation makes it plain what numbers we are talking about while making the order in which to compute them ambiguous. Prefix and postfix notation make the order in which to compute plain while making the numbers ambiguous. Python would already have multiline lambdas if it were not for the difficulties caused by the syntactic whitespace. (Proposals do exist for pulling this kind of thing off without necessarily adding explicit block delimiters.)
I find it easier to write conditions where I want something to occur if a condition is false much easier to write with the unless statement in Ruby than the semantically equivalent “if-not” construction in Ruby or other languages for example. If most of the languages that people are using today are equal in power, how can the syntax of each language be considered a trivial thing? After specific features like blocks and inheritance mechanisms etc. syntax is the most important part of a language,hardly a superficial thing.
What is superficial are the aesthetic qualities of beauty that we ascribe to syntax. Aesthetics have nothing to do with how our cognition works, syntax does.
Surprised to see nothing mentioned of ruby’s “method missing” mechanism. I’d give examples of the find_by_… methods in Rails, as an example of the power of that language feature. My guess is that something similar could be implemented in Python, but to my knowledge it isn’t there natively.
回答 25
Paul Graham的累加器生成器问题证明了Python和Ruby在lambda上的另一个区别。转载在这里:
Another difference in lambdas between Python and Ruby is demonstrated by Paul Graham’s Accumulator Generator problem. Reprinted here:
Write a function foo that takes a number n and returns a function that takes a number i, and returns n incremented by i.
Note: (a) that’s number, not integer, (b) that’s incremented by, not plus.
In Ruby, you can do this:
def foo(n)
lambda {|i| n += i }
end
In Python, you’d create an object to hold the state of n:
class foo(object):
def __init__(self, n):
self.n = n
def __call__(self, i):
self.n += i
return self.n
Some folks might prefer the explicit Python approach as being clearer conceptually, even if it’s a bit more verbose. You store state like you do for anything else. You just need to wrap your head around the idea of callable objects. But regardless of which approach one prefers aesthetically, it does show one respect in which Ruby lambdas are more powerful constructs than Python’s.
回答 26
python已命名可选参数
def func(a, b=2, c=3):print a, b, c
>>> func(1)123>>> func(1, c=4)124
What blocks Ruby, Python to get Javascript V8 speed?
Nothing.
Well, okay: money. (And time, people, resources, but if you have money, you can buy those.)
V8 has a team of brilliant, highly-specialized, highly-experienced (and thus highly-paid) engineers working on it, that have decades of experience (I’m talking individually – collectively it’s more like centuries) in creating high-performance execution engines for dynamic OO languages. They are basically the same people who also created the Sun HotSpot JVM (among many others).
Lars Bak, the lead developer, has been literally working on VMs for 25 years (and all of those VMs have lead up to V8), which is basically his entire (professional) life. Some of the people writing Ruby VMs aren’t even 25 years old.
Are there any Ruby / Python features that are blocking implementation of optimizations (e.g. inline caching) V8 engine has?
Given that at least IronRuby, JRuby, MagLev, MacRuby and Rubinius have either monomorphic (IronRuby) or polymorphic inline caching, the answer is obviously no.
Modern Ruby implementations already do a great deal of optimizations. For example, for certain operations, Rubinius’s Hash class is faster than YARV’s. Now, this doesn’t sound terribly exciting until you realize that Rubinius’s Hash class is implemented in 100% pure Ruby, while YARV’s is implemented in 100% hand-optimized C.
So, at least in some cases, Rubinius can generate better code than GCC!
Or this is rather matter of resources put into the V8 project by Google.
Yes. Not just Google. The lineage of V8’s source code is 25 years old now. The people who are working on V8 also created the Self VM (to this day one of the fastest dynamic OO language execution engines ever created), the Animorphic Smalltalk VM (to this day one of the fastest Smalltalk execution engines ever created), the HotSpot JVM (the fastest JVM ever created, probably the fastest VM period) and OOVM (one of the most efficient Smalltalk VMs ever created).
In fact, Lars Bak, the lead developer of V8, worked on every single one of those, plus a few others.
There’s a lot more impetus to highly optimize JavaScript interpretors which is why we see so many resources being put into them between Mozilla, Google, and Microsoft. JavaScript has to be downloaded, parsed, compiled, and run in real time while a (usually impatient) human being is waiting for it, it has to run WHILE a person is interacting with it, and it’s doing this in an uncontrolled client-end environment that could be a computer, a phone, or a toaster. It HAS to be efficient in order to run under these conditions effectively.
Python and Ruby are run in an environment controlled by the developer/deployer. A beefy server or desktop system generally where the limiting factor will be things like memory or disk I/O and not execution time. Or where non-engine optimizations like caching can be utilized. For these languages it probably does make more sense to focus on language and library feature set over speed optimization.
The side benefit of this is that we have two great high performance open source JavaScript engines that can and are being re-purposed for all manner of applications such as Node.js.
关于技术细节,我对Ruby不太了解,但是Python在很多地方都可以使用优化功能(Google项目Unladen Swallow在开始努力之前就开始实现这些功能)。这是他们计划的一些优化。如果为CPython实现JIT la PyPy,我可以看到Python在将来获得V8的速度,但这在未来几年似乎不太可能(目前的重点是采用Python 3,而不是JIT)。
A good part of it has to do with community. Python and Ruby for the most part have no corporate backing. No one gets paid to work on Python and Ruby full-time (and they especially don’t get paid to work on CPython or MRI the whole time). V8, on the other hand, is backed by the most powerful IT company in the world.
Furthermore, V8 can be faster because the only thing that matters to the V8 people is the interpreter — they have no standard library to work on, no concerns about language design. They just write the interpreter. That’s it.
It has nothing to do with intellectual property law. Nor is Python co-developed by Google guys (its creator works there along with a few other committers, but they don’t get paid to work on Python).
Another obstacle to Python speed is Python 3. Its adoption seems to be the main concern of the language developers — to the point that they have frozen development of new language features until other implementations catch up.
On to the technical details, I don’t know much about Ruby, but Python has a number of places where optimizations could be used (and Unladen Swallow, a Google project, started to implement these before biting the dust). Here are some of the optimizations that they planned. I could see Python gaining V8 speed in the future if a JIT a la PyPy gets implemented for CPython, but that does not seem likely for the coming years (the focus right now is Python 3 adoption, not a JIT).
Many also feel that Ruby and Python could benefit immensely from removing their respective global interpreter locks.
You also have to understand that Python and Ruby are both much heavier languages than JS — they provide far more in the way of standard library, language features, and structure. The class system of object-orientation alone adds a great deal of weight (in a good way, I think). I almost think of Javascript as a language designed to be embedded, like Lua (and in many ways, they are similar). Ruby and Python have a much richer set of features, and that expressiveness is usually going to come at the cost of speed.
Performance doesn’t seem to be a major focus of the core Python developers, who seem to feel that “fast enough” is good enough, and that features that help programmers be more productive are more important than features that help computers run code faster.
Indeed, however, there was a (now abandoned) Google project, unladen-swallow, to produce a faster Python interpreter compatible with the standard interpreter. PyPy is another project that intends to produce a faster Python. There is also Psyco, the forerunner of PyPy, which can provide performance boosts to many Python scripts without changing out the whole interpreter, and Cython, which lets you write high-performance C libraries for Python using something very much like Python syntax.
Misleading question. V8 is a JIT (a just in time compiler) implementation of JavaScript and in its most popular non-browser implementation Node.js it is constructed around an event loop. CPython is not a JIT & not evented. But these exist in Python most commonly in the PyPy project – a CPython 2.7 (and soon to be 3.0+) compatible JIT. And there are loads of evented server libraries like Tornado for example. Real world tests exist between PyPy running Tornado vs Node.js and the performance differences are slight.
I just ran across this question and there is also a big technical reason for the performance difference that wasn’t mentioned. Python has a very large ecosystem of powerful software extensions, but most of these extensions are written in C or other low-level languages for performance and are heavily tied to the CPython API.
There are lots of well-known techniques (JIT, modern garbage collector, etc) that could be used to speed up the CPython implementation but all would require substantial changes to the API, breaking most of the extensions in the process. CPython would be faster, but a lot of what makes Python so attractive (the extensive software stack) would be lost. Case in point, there are several faster Python implementations out there but they have little traction compared to CPython.
Because of different design priorities and use case goals I believe.
In general main purpose of scripting (a.k.a. dynamic) languages is to be a “glue” between calls of native functions. And these native functions shall a) cover most critical/frequently used areas and b) be as effective as possible.
Here is an example:
jQuery sort causing iOS Safari to freeze
The freeze there is caused by excessive use of get-by-selector calls. If get-by-selector would be implemented in native code and effectively it will be no such problem at all.
Consider ray-tracer demo that is frequently used demo for V8 demonstration. In Python world it can be implemented in native code as Python provides all facilities for native extensions. But in V8 realm (client side sandbox) you have no other options rather than making VM to be [sub]effective as possible. And so the only option see ray-tracer implementation there is by using script code.
So different priorities and motivations.
In Sciter I’ve made a test by implementing pretty much full jQurey core natively. On practical tasks like ScIDE (IDE made of HTML/CSS/Script) I believe such solution works significantly better then any VM optimizations.
As other people have mentioned, Python has a performant JIT compiler in the form of PyPy.
Making meaningful benchmarks is always subtle, but I happen to have a simple benchmark of K-means written in different languages – you can find it here. One of the constraints was that the various languages should all implement the same algorithm and should strive to be simple and idiomatic (as opposed to optimized for speed). I have written all the implementations, so I know I have not cheated, although I cannot claim for all languages that what I have written is idiomatic (I only have a passing knowledge of some of those).
I do not claim any definitive conclusion, but PyPy was among the fastest implementations I got, far better than Node. CPython, instead, was at the slowest end of the ranking.
Also, there the problem of perceived performance : since V8 is natively non blocking, Web dev leads to more performant projects because you save the IO wait. And V8 is mainly used for dev Web where IO is key, so they compare it to similar projects. But you can use Python in many, many other areas than web dev. And you can even use C extensions for a lot of tasks, such as scientific computations or encryption, and crunch data with blazing perfs.
But on the web, most popular Python and Ruby projects are blocking. Python, especially, has the legacy of the synchronous WSGI standard, and frameworks like the famous Django are based on it.
You can write asynchronous Python (like with Twisted, Tornado, gevent or asyncio) or Ruby. But it’s not done often. The best tools are still blocking.
However, they are some reasons for why the default implementations in Ruby and Python are not as speedy as V8.
Experience
Like Jörg W Mittag pointed out, the guys working on V8 are VM geniuses. Python is dev by a bunch a passionate people, very good in a lot of domains, but are not as specialized in VM tuning.
Resources
The Python Software foundation has very little money : less than 40k in a year to invest in Python. This is kinda crazy when you think big players such as Google, Facebook or Apple are all using Python, but it’s the ugly truth : most work is done for free. The language that powers Youtube and existed before Java has been handcrafted by volunteers.
They are smart and dedicated volunteers, but when they identify they need more juice in a field, they can’t ask for 300k to hire a top notch specialist for this area of expertise. They have to look around for somebody who would do it for free.
While this works, it means you have to be very a careful about your priorities. Hence, now we need to look at :
Objectives
Even with the latest modern features, writing Javascript is terrible. You have scoping issues, very few collections, terrible string and array manipulation, almost no stdlist apart from date, maths and regexes, and no syntactic sugar even for very common operations.
But in V8, you’ve got speed.
This is because, speed was the main objective for Google, since it’s a bottleneck for page rendering in Chrome.
In Python, usability is the main objective. Because it’s almost never the bottleneck on the project. The scarce resource here is developer time. It’s optimized for the developer.
Because JavaScript implementations need not care about backwards compatibility of their bindings.
Until recently the only users of the JavaScript implementations have been web browsers. Due to security requirements, only the web browser vendors had the privilege to extend the functionality by writing bindings to the runtimes. Thus there was no need keep the C API of the bindings backwards compatible, it was permissible to request the web browser developers update their source code as the JavaScript runtimes evolved; they were working together anyways. Even V8, which was a latecomer to the game, and also lead by a very very experienced developer, have changed the API as it became better.
OTOH Ruby is used (mainly) on the server-side. Many popular ruby extensions are written as C bindings (consider an RDBMS driver). In other words, Ruby would have never succeeded without maintaining the compatibility.
Today, the difference still exist to some extent. Developers using node.js are complaining that it is hard to keep their native extensions backwards compatible, as V8 changes the API over time (and that is one of the reasons node.js has been forked). IIRC ruby is still taking a much more conservative approach in this respect.
V8 is fast due to the JIT, Crankshaft, the type inferencer and data-optimized code. Tagged pointers, NaN-tagging of doubles.
And of course it does normal compiler optimizations in the middle.
The plain ruby, python and perl engines don’t do neither of the those, just minor basic optimizations.
The only major vm which comes close is luajit, which doesn’t even do type inference, constant folding, NaN-tagging nor integers, but uses similar small code and data structures, not as fat as the bad languages.
And my prototype dynamic languages, potion and p2 have similar features as luajit, and outperform v8. With an optional type system, “gradual typing”, you could easily outperform v8, as you can bypass crankshaft. See dart.
The known optimized backends, like pypy or jruby still suffer from various over-engineering techniques.
cd impls/haxe
# Neko
make all-neko
neko ./stepX_YYY.n
# Python
make all-python
python3 ./stepX_YYY.py
# C++
make all-cpp
./cpp/stepX_YYY
# JavaScript
make all-js
node ./stepX_YYY.js
干草
MAL的Hy实现已经用Hy 0.13.0进行了测试
cd impls/hy
./stepX_YYY.hy
IO
已使用IO版本20110905测试了MAL的IO实现
cd impls/io
io ./stepX_YYY.io
珍妮特
MAIL的Janet实现已经使用Janet版本1.12.2进行了测试
cd impls/janet
janet ./stepX_YYY.janet
Java 1.7
mal的Java实现需要maven2来构建
cd impls/java
mvn compile
mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY
# OR
mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY -Dexec.args="CMDLINE_ARGS"
Java,将Truffle用于GraalVM
这个Java实现可以在OpenJDK上运行,但是多亏了Truffle框架,它在GraalVM上的运行速度可以提高30倍。它已经在OpenJDK 11、GraalVM CE 20.1.0和GraalVM CE 21.1.0上进行了测试
cd impls/java-truffle
./gradlew build
STEP=stepX_YYY ./run
JavaScript/节点
cd impls/js
npm install
node stepX_YYY.js
朱莉娅
Mal的Julia实现需要Julia 0.4
cd impls/julia
julia stepX_YYY.jl
JQ
针对1.6版进行了测试,IO部门存在大量作弊行为
cd impls/jq
STEP=stepA_YYY ./run
# with Debug
DEBUG=true STEP=stepA_YYY ./run
科特林
MAL的Kotlin实现已经使用Kotlin 1.0进行了测试
cd impls/kotlin
make
java -jar stepX_YYY.jar
LiveScript
已使用LiveScript 1.5测试了mal的LiveScript实现
cd impls/livescript
make
node_modules/.bin/lsc stepX_YYY.ls
徽标
MAL的Logo实现已经用UCBLogo 6.0进行了测试
cd impls/logo
logo stepX_YYY.lg
路亚
Mal的Lua实现已经使用Lua 5.3.5进行了测试。该实现需要安装luarock
cd impls/lua
make # to build and link linenoise.so and rex_pcre.so
./stepX_YYY.lua
cd impls/miniMAL
# Download miniMAL and dependencies
npm install
export PATH=`pwd`/node_modules/minimal-lisp/:$PATH
# Now run mal implementation in miniMAL
miniMAL ./stepX_YYY
make MAL_IMPL=IMPL "test^mal^step2"
# e.g.
make "test^mal^step2" # js is default
make MAL_IMPL=ruby "test^mal^step2"
make MAL_IMPL=python "test^mal^step2"
启动REPL
要在特定步骤中启动实施的REPL,请执行以下操作:
make "repl^IMPL^stepX"
# e.g
make "repl^ruby^step3"
make "repl^ps^step4"
如果您省略了这一步,那么stepA使用的是:
make "repl^IMPL"
# e.g
make "repl^ruby"
make "repl^ps"
# install pyroscope
brew install pyroscope-io/brew/pyroscope
# start pyroscope server:
pyroscope server
# in a separate tab, start profiling your app:
pyroscope exec python manage.py runserver # If using Python
pyroscope exec rails server # If using Ruby# If using Pyroscope cloud add flags for server address and auth token# pyroscope exec -server-address "https://your_company.pyroscope.cloud" -auth-token "ps-key-1234567890" python manage.py runserver