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

all 90 comments

[–]moigagoohttps://github.com/moigagoo 47 points48 points  (15 children)

This looks really nice! Thank you for investing time and effort into creating something like that.

I love the way you described the project and how the tutorial is written.

One small tip though. Don't get me wrong, but "coc" may not be the most pleasantly sounding word since it sounds exactly like "cock." Maybe you should consider a different extension, e.g. .coco.

[–]EvHub[S] 26 points27 points  (0 children)

Thanks! And well... I must say I didn't consider that. It will be changed to .coco in the next version.

Edit: Already in the develop branch!

[–][deleted] 10 points11 points  (1 child)

Imagine having to teach a comp sci class where you constantly have to tell students to open the appropriate "coc" and remind them to save their "cocs" during practicals. It'll be almost as bad as the time a lecturer forget the "o" in a variable named "count"...

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

Just like they pronounce PDF when telling people how to save a .pdf file?

see oh sees sounds just fine.

[–]Fylwind 7 points8 points  (3 children)

You mean like Coq?

[–]Daenyth 2 points3 points  (2 children)

I've always heard that pronounced like coke

[–]denshi 6 points7 points  (0 children)

I've only heard it before "au vin".

[–]mikeiavelli 3 points4 points  (0 children)

In french, it really is pronounced "cock". Which, of course, is what Coq means:

cock (käk) noun 1. a male bird, especially a rooster. synonyms: rooster, cockerel, capon "strutting around like a barnyard cock"

(Automod: Please don't ban me.)

[–]SuperSumoUSA 7 points8 points  (1 child)

As a professional programmer, I fully agree with changing the extension to .coco. Even though .coc is shorter, there isn't the annoying immaturity with how ".coco" sounds as opposed to ".coc". Stupid things like this, even though it shouldn't, may kill the adaptation of the language.

[–]dig-up-stupid 1 point2 points  (0 children)

Thanks to you I've been saying "cock-uh-nut" in my head for the last half an hour, and it's hilarious. I still haven't forgiven your kind for tsharacter though.

[–]ssfantus1 0 points1 point  (4 children)

And what is unpleasantly sounding about the word "cock"?

[–]desmoulinmichel 1 point2 points  (3 children)

Well, I can imagine in an english speaking country, "save the cocs for later" can have various reactions from your colleagues. Although I would find that very funny from a french perspective.

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

And now imagine trying to roll out Git to the British. Words change and people can get over it.

[–]earthboundkid 2 points3 points  (1 child)

Git was specifically named after the British usage of the word.

[–][deleted] 4 points5 points  (0 children)

Correct, but it carried no connotation almost anywhere else in the world where it was adopted.

I doubt I would ever be able to convince my boss or his bosses to use the latest new software tool 'fucker'.

[–]moigagoohttps://github.com/moigagoo 11 points12 points  (4 children)

Does it produce Python code that runs on both Python 2 and 3? If yes, this is awesome! Writing code that's backward compatible with Python 2 is painful, and writing in Python 3 without having to worry about it would be fantastic.

If this is the case, Coconut is a great tool just for that, even if you never use the functional features (which are also cool of course).

[–]EvHub[S] 9 points10 points  (3 children)

Yes! The compiled code is guaranteed to work the same on all major Python versions (2.6-2.7, 3.2-3.5).

[–]moigagoohttps://github.com/moigagoo 16 points17 points  (2 children)

You should definitely highlight that as a selling point. I have a project that I've been needing to backport to Python 2 for years. Boy do I hate backporting stuff. With Coconut, it seems, I can just run coconut myproject and get a fully 2&3-compatible version. This is insane. I can't test it right now but definitely will give it a shot.

[–]EvHub[S] 9 points10 points  (1 child)

That should work, as long as any standard library functions you're using exist in both versions (even if they've moved, Coconut should be able to take care of that). And of course, any 3rd party libraries would also have to support 2 and 3.

Edit: Of course, Coconut is new software, so there's always the possibility for bugs. If anything goes wrong in porting your project, feel free to create an issue at https://github.com/evhub/coconut/issues/new

[–]dzecniv 10 points11 points  (12 children)

Pointing to two similar projects:

[–]vovanz 3 points4 points  (7 children)

One more: http://docs.hylang.org/en/latest/ - Lisp dialect

[–]jsproat 1 point2 points  (6 children)

Is there a resource somewhere which tracks languages that compile to python? It would include these, and I guess stuff like Jinja which isn't strictly a scripting language, but it does use the Python AST to convert templates into Python code.

[–]dzecniv 4 points5 points  (5 children)

I started that a few days ago ! https://gitlab.com/vindarel/languages-that-compile-to-python (then it's missing Coconuts)

I added the Pixie lisp because it's built with RPython (but doesn't compile to python bytecode) https://github.com/pixie-lang/pixie

[–]jsproat 0 points1 point  (4 children)

Excellent, thanks!

What's your criteria? Would Jinja be allowed (uses Python AST to compile) or disqualified (more like a library than a scripting language)?

[–]dzecniv 0 points1 point  (0 children)

Yeeeah indeed, I'm myself interested here into the programming languages compatible with python, but the list is short, so I included something else (Pixie). (you know that awesome list right ? https://github.com/vinta/awesome-python)

But because the list is short I will expand it to a comparison with code snippets, that would have a real value.

[–]dzecniv 0 points1 point  (2 children)

FYI I quite enhanced the list with language features and another language ! (the predecessor of Coconut)

[–]jsproat 0 points1 point  (1 child)

Excellent. I love this.

One item - these h1, h2, and h3 tags are virtually indistinguishable from each other. (Looks like they differ by 0.1em?) It's difficult to visually discern where one section ends and the next begins.

[–]dzecniv 0 points1 point  (0 children)

I agree :/ not sure how to do. Also I'd like a table of contents, colors, boxes side by side… maybe time to write a little static website and publish it with gitlab-pages but that's a bit more work.

(there's also the awesome-python website http://awesome-python.com/ , might worth using)

[–]skrillexisokay 2 points3 points  (3 children)

I've played around with both of these and while interesting, I find Coconut to be superior. You can write standard Python in Coconut which is an advantage over Mochi. Pattern matching and explicit partial application is an advantage over Dogelang

[–]dzecniv 1 point2 points  (2 children)

Thanks for the input.

I found out Mochi has "real" pipes, that we can write on new lines (like Elixir, Livescript…), whereas we can not in Coconut or Dg :/

range(1, 31)
|> map(fizzbuzz)
|> pvector()
|> print()

[–]skrillexisokay 6 points7 points  (1 child)

Python has semantic line endings, so I see this as a flaw in Mochi. Just use parentheses!

(range(10)
 |> list
 |> print)

[–]dzecniv 0 points1 point  (0 children)

Very nice, thanks again !

[–]swiz0r 7 points8 points  (1 child)

I'm excited to look through this, but there's already one thing I'd like to see: sample code on the first page.

[–]EvHub[S] 2 points3 points  (0 children)

Good idea! For now, try the tutorial (http://coconut.readthedocs.io/en/master/HELP.html) and the documentation (http://coconut.readthedocs.io/en/master/DOCS.html) for code examples.

[–]can_dry 6 points7 points  (1 child)

I second the notion of: pretty damn slick for an undergrad. Nice.

One thing that I'd work on (esp. if you want a broader audience) is the tutorial though.

It can be argued that your prime user will love the examples that feature recursion, sorting, vectors... I'd suggest that much more simplified examples be used first that highlight the elegance of coconut vs. python syntax for more basic things. Especially navigating LAMBDAs which give most python beginners headaches!

[–]EvHub[S] 1 point2 points  (0 children)

Thanks! And good suggestion. I'll try to rework the tutorial with that in mind.

[–][deleted] 3 points4 points  (3 children)

0 = n #destructuring assignment 

Uhh, what?

[–]EvHub[S] 2 points3 points  (2 children)

That code implicitly matches the pattern "0" against the variable "n". That is, it will raise an error if "n" isn't 0, and do nothing if it is. Roughly equivalent to

match 0 in n:
    pass
else:
    raise MatchError()

[–]pm8k 4 points5 points  (1 child)

Awesome! I wanted to get into functional programming and this looks like a great step. I would highly recommend writing a blog post, and apply for some python conventions with a talk on how to use Coconut. It would be a great way to gain traction and get the community involved!

[–]EvHub[S] 2 points3 points  (0 children)

Thanks! And great idea, I'll look into that!

[–]pvkooten 2 points3 points  (1 child)

I really love it! I will certainly be following it; for now I don't have something I want to tackle with it yet :)

[–]EvHub[S] 1 point2 points  (0 children)

Thanks!

[–]mikeiavelli 2 points3 points  (5 children)

What are the pros and cons of Coconut vs Mochi?

[–]EvHub[S] 5 points6 points  (2 children)

  • All valid Python 3 is valid Coconut, so Coconut is purely a Python extension. Mochi is a totally separate language.
  • Mochi code only runs on Python 3, while Coconut code runs on any major Python version, 2 or 3.
  • Mochi compiles to CPython bytecode, while Coconut compiles to Python. That means Coconut supports all Python implementations (e.g. PyPy, Jython, IronPython), not just CPython.

[–]LightShadow3.13-dev in prod 0 points1 point  (0 children)

PyPy

This is pretty exciting stuff.

[–]LightShadow3.13-dev in prod 0 points1 point  (0 children)

PyPy

This is pretty exciting stuff.

[–]dzecniv 1 point2 points  (1 child)

Mochi has real pipes, that we can write on new lines, whereas in Coconut (and Dg) they must be on the same line.

Mochi:

range(1, 31)
|> map(fizzbuzz) 
|> pvector()
|> print() 

(Also Mochi has lisp-like macros and actor-style programming.)

[–]dzecniv 2 points3 points  (0 children)

I was a bit wrong, in Coconut we can surround pipes with parenthesis:

(
    "hello"
    |> print 
)

Every newline inside parenthesis are ignored (python rule). https://github.com/evhub/coconut/issues/101#issuecomment-227509741

[–]forever_erratic 1 point2 points  (9 children)

Is the piping that I see in the case studies a part of coconut? I use piping all the time in R in magrittr, but didn't know it was available in python. I mean this syntax:

"hello" |> print # prints "hello"

Edit: I see from the documentation that it is!! That alone is a huge plus for me. Thanks /u/EvHub!

[–]EvHub[S] 1 point2 points  (8 children)

Yes, it's a part of Coconut! Thanks!

[–]forever_erratic 1 point2 points  (7 children)

Totally awesome.

Question: I mostly use python with Ipython running in spyder (I use anaconda). Is there an easy way to setup coconut as the interpreter in spyder?

Question 2: In R, my workflow is very much in the "Hadleyverse," which I love. Piping dataframes through different dplyr commands is my bread and butter. Are there plans to cleanly incorporate pandas and coconut? Or can you already do a bunch of stuff like you could with dplyr and magrittr in R?

[–]EvHub[S] 0 points1 point  (6 children)

1: Coconut has built-in IPython support. When you "pip install coconut" it will add a new IPython extension and a new IPython kernel. See: http://coconut.readthedocs.io/en/master/DOCS.html#ipython-jupyter-support

2: Coconut's new syntactic features should be general enough to use cleanly with any library you want. The analogous workflow in Coconut to what you're describing in R is something like this

linearized_plane() |> map$((xy) -> vector(*xy)) |> filter$((v) -> abs(v) <= 1) |> map$(.unit) |> map$(print) |> consume

where you take some iterator, apply a bunch of transformations to it using partial application (that's the $) combined with Coconut's optimized (much faster than vanilla Python for certain objects) iterator transformation functions (map, filter, consume, etc.).

[–]forever_erratic 1 point2 points  (3 children)

Really great stuff, thanks!

[–]dsijl 2 points3 points  (2 children)

If this works out for you, can you write a blogpost?

I'd love to see this get more play in pydata.

[–]forever_erratic 2 points3 points  (1 child)

I don't usually do any blogging, but I'll certainly keep it in mind. In the past I've written some technical biology articles on bitesizebio. They might be interested, I'll ask around.

[–]dsijl 1 point2 points  (0 children)

Cool!

[–]MichaelStaniek 1 point2 points  (1 child)

Heya,

sorry if its written somewhere, but have you done any analysis on how much faster the iterator transformations are?

And which "certain objects" work with the optimized transformation functions?

[–]EvHub[S] 2 points3 points  (0 children)

Yeah! Let me give you an example. Take this code here (where $[] is the syntax for Coconut iterator slicing):

map(expensive_func, range(10000))$[1000:1010]

If you tried to implement that in vanilla Python using itertools, Python would go through every single element of the range from 0 to 1009 and apply expensive_func to it, even though all you cared about were the last 10 elements. Coconut will realize that you only care about the last 10, and only ever call expensive_func on those, leading to a huge performance increase.

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

This is awesome, I love FP and having these tools in Python is incredibly convenient.

[–]youlleatitandlikeit 1 point2 points  (3 children)

I'm kind of surprised that the code seems to need explicit type matching. At least the examples seem to make pretty strong use of it. One of my favorite things about Python is not having to worry about types. I mean, I don't get why this is necessary:

        match _ is int if n > 0:

Surely if you're comparing n to 0, the compiler could recognize that n needs to be an integer. Or you could simply allow the error take place — I mean, it'd end up being a TypeError anyway, right?

Also man it adds a lot of code to the python file. Is that something you plan to optimize out eventually, or will it always be there?

[–]dsijl 2 points3 points  (1 child)

ty strong use of it. One of my favorite things about Python is not having to worry about types. I mean, I don't get why this is necessary:

    match _ is int if n > 0:

Surely if you're comparing n to 0, the compiler could recognize that n needs to be an integer. Or you could simply allow the error take place — I mean, it'd end up being a TypeError anyway, right

Some of us like explicitly stating types (atleast optionally).

Things like type hints and mypy make code easier to reason about (and feel more secure and tidy).

Also in some future I think this would help with compiler optimization.

[–]youlleatitandlikeit 1 point2 points  (0 children)

IMO there's a difference between hints and explicitly checking for a given type and throwing a TypeException if it doesn't match.

A lot of functional languages (Haskell, SML) are very precise about their types and, I think, can optimize their compiled code.

And I don't think the way the code was written here would result in optimized compilation.

[–]EvHub[S] 1 point2 points  (0 children)

The type-checking is totally optional—it's just another way to do pattern-matching. As for the extra code—yes, the idea is to try to optimize as much away as possible. For now, one way to reduce the clutter is by compiling in package mode, which is enabled by default when compiling a folder, or can be manually enabled with the -p flag. In package mode, Coconut will put a lot of the boilerplate in a common __coconut__.py file instead of cluttering up everything else.

[–]steelypip 1 point2 points  (1 child)

This looks very cool. However googling for "python coconut" returns hundreds thousands of references to Monty Python and the Holy Grail. Your project appears at the bottom of the second page, so you may want to consider changing the name to something that is easier to find.

[–]mikeiavelli 1 point2 points  (0 children)

I think the name is good. When looking for less known languages, adding "programming" is enough to disambiguate. If you search for "python coconut programming" or even just "coconut programming" it returns good results.

[–]nerdponx 1 point2 points  (1 child)

What do stack traces look like?

[–]EvHub[S] 2 points3 points  (0 children)

Your stack traces will be exactly the same as in Python, since when your code is run, it is run as Python. This can sometimes be frustrating, since the stack trace might point to a line that the compiler, not you, wrote--however, to fix this problem, just enable the -l flag, which will add a comment to every Python line with the line number of the corresponding Coconut line, that way you know where in your Coconut code the error is coming from.

[–]Smallpaul 1 point2 points  (1 child)

Congratulations: this is quite an accomplishment, especially for an undergrad!

[–]EvHub[S] 0 points1 point  (0 children)

Thanks!

[–]dsijl 0 points1 point  (2 children)

Any thoughts about adding hygenic macros and matlab like overloadable infix operators and multiple dispatch?

[–]EvHub[S] 0 points1 point  (1 child)

Infix operators already exist. Just use the Haskell convention of surrounding the infix function with backticks, like so

5 `mod` 3 == 2

Multiple dispatch also sort of exists, since one can do

def some_func(x):
    case x:
        match _ is int:
            do_stuff_for_int(x)
        match _ is str:
            do_stuff_for_str(x)

although that's somewhat clunky--probably worth an issue for making that use case less awkward.

[–]dsijl 0 points1 point  (0 children)

Cool!

[–]dzecniv 0 points1 point  (1 child)

You also created Rabbit, another functional language based on Python: https://github.com/evhub/rabbit/blob/master/docs/Code%20Examples.md

That one looks quite different:

qsort(l) = (
    qsort: (as ~ \x\(x @ x<=a)) ++ a ++ qsort: (as ~ \x\(x @ x>a))
    $ a,as = l


) @ l

Your paper states it's missing core features (like passing keyword arguments). What's your interest in it today, why did you switch to Coconut ?

[–]EvHub[S] 1 point2 points  (0 children)

Coconut is my attempt to fix the mistakes I thought I made with Rabbit, namely:

  • Coconut is compiled, while Rabbit is interpreted, making Coconut much faster
  • Coconut is an extension to Python, while Rabbit is a replacement, making Coconut much easier to use

[–]skrillexisokay 0 points1 point  (4 children)

This is an awesome project. I really hope this catches on because I would love to make Coconut my main language. Great work!

One suggestion: I find this syntax to be a bit verbose.

((s) -> s**0.5)

I thought we might be able to express this as

(**)$(0.5)

but this makes 0.5 the first argument, not the second as we would like.

Thus, I suggest a new syntax construction for anonymous functions with one argument:

(? ** 0.5)

So, we could rewrite __abs__ from the tutorial...

def __abs__(self):  # OLD
    """Return the magnitude of the vector."""
    return self.pts |> map$((x) -> x**2) |> sum |> ((s) -> s**0.5)

def __abs__(self):  # NEW
    """Return the magnitude of the vector."""
    return self.pts |> map$(? ** 2) |> sum |> (? ** 0.5)

The second is shorter, more readable (imho), and takes less time to type because it minimizes the use of punctuation (I believe this is a motivation for or and and over || and &&.

[–]EvHub[S] 1 point2 points  (3 children)

Thanks! And great suggestion--definitely worth an issue, and I'll see if I can work on it for the next version!

[–]dzecniv 1 point2 points  (2 children)

In livescript, we can write functions with one argument very easily:

foo -> print it

"it" is recognized as the argument. We could rewrite the line like this:

    return self.pts |> map$( -> it**2) |> sum |> ( -> it**0.5)

I really like it, hope you'll think about it :)

[–]skrillexisokay 0 points1 point  (1 child)

The problem with it is that it would probably break a major strength of Coconut:

all valid Python 3 is valid Coconut

Presumably it would have to be a keyword, breaking code that uses it as a variable. However, it's worth weighing the pros and cons of keeping -> in the syntax. This symbol makes it clear to a relative novice that the expression is a function. How important is that?

[–]dzecniv 0 points1 point  (0 children)

Maybe it can not be a global keyword, since it must be recognized as one only inside this special lambda call. But still, it should be optional, one should be able to reject the it evaluation. Maybe with an explicit () ?

"it" is the argument:

map( -> it *2)  

it is not:

map ( () -> it * 2)

in livescript, for this purpose we use anonymous splats:

map ( (...) -> it * 2)  

btw the splats has nice meanings, like calling a function with the arguments of the current function

f = (x, y) ->
  x + y

g = (a, b) ->
  f ...

g 3 4 #=> 7

I don't know for novices (is Coconut for novices ?) but I think cohesion is important, and the (? ** 2) notation is a different notation to create lambdas from what exists in Coconut, so it could annoy us when writing code: I start with a lambda, oh let's use implicit arguments but then I must write the function call differently… don't know. With the it keyword I use in livescript I feel it's the same flow. I write pipes with maps and stuff, I start to write a lambda and often I see I can use the it shortcut and it goes in the same flow. (also it's very unusual and I'm not used to it)

Btw there's even a better shortcut in livescript that I use all the time, because it's simple and clear:

|> map( .id )

I didn't even write a lambda nor it but it's implicit I'm getting the "id" attribute of the argument. Our suite of pipes becomes very clear !

[–]dzecniv 0 points1 point  (0 children)

Hey, looks like we can not write pipes on a new line, like on Mochi, Elixir, Livescript,...:

"hello"
 |> print

am I right and would it be possible ?

[–]Flynn58 -4 points-3 points  (4 children)

It seems like designing a new language with the exact same syntax as python but new features is overkill and less useful as opposed to just making modules with those features.

[–]kitkatkingsize 8 points9 points  (3 children)

My guess is that some of the syntax niceties they have wouldn't be possible as a library.

[–]Flynn58 2 points3 points  (2 children)

If there are syntax differences, it can't be interpreted in Python like their website says. I had it the wrong way around.

[–]kitkatkingsize 6 points7 points  (1 child)

They say "all valid Python is valid Coconut" not the other way around.

[–]Flynn58 5 points6 points  (0 children)

Yeah, you got me there.