5 ms·
you are right that python is an opinionated choice, but that particularly chosen philosophy is what people disagree with. the philosophy is somewhat stubborn as
by nikofeyn 8y ago
you are right that python is an opinionated choice, but that particularly chosen philosophy is what people disagree with. the philosophy is somewhat stubborn as well.
and i think you are leaving out functional languages which share python's readability, if not surpass it, while remaining much more expressive. that's f# and ocaml.
f#, in my opinion, is superior in everyway to python and subsumes python's abilities of readability, easiness, oop, and scripting, while greatly raising the ceiling of possibility. it's criminally underused, especially in areas where python has been chosen.
and i disagree lisp is harder to get into. racket is just as easy to learn as python, if not easier, due to its regularity. the how to code / systematic program design course on edX and the book how to design programs showcases this.
- sametmax 8y agoI heard good things about F# and I did like C#, so I wanted to give an honest look at your arguments. The first thing I checked is your very vocal assurance that F# is a better scripting language than Python. That seemed very weird to me, after all it's Python strong point. Since I script a lot, I looked for the most popular F# lib to parse script arguments. Argu seems the winner, according to http://fsharpworks.com/survey.html http://fsharpworks.com/survey.html. Their tutorial is pretty good (https://fsprojects.github.io/Argu/tutorial.html https://fsprojects.github.io/Argu/tutorial.html), and here is their hello world. 24 lines of, packing a dense symbology and using a lot of the specific language features: open Argu type CLIArguments = | Working_Directory of path:string | Listener of host:string * port:int | Data of base64:byte[] | Port of tcp_port:int | Log_Level of level:int | Detach with interface IArgParserTemplate with member s.Usage = match s with | Working_Directory _ -> "specify a working directory." | Listener _ -> "specify a listener (hostname : port)." | Data _ -> "binary data in base64 encoding." | Port _ -> "specify a primary port." | Log_Level _ -> "set the log level." | Detach _ -> "detach daemon from console." let parser = ArgumentParser.Create<CLIArguments>(programName = "gadget.exe") let results = parser.Parse [| "--detach" ; "--listener" ; "localhost" ; "8080" |] printfn "%A" results.GetAllResults();; The same thing with click, the Python most popular solution, is 11 lines, and it's shaped around almost only regular calls and parameters: import click as cli, base64, urllib.parse as url @cli.command("gadget.exe") @cli.option('--working-directory', help='specify a working directory.', type=cli.File('rb')) @cli.option('--listener', help="specify a listener (hostname : port)", type=url.urlparse) @cli.option('--data', help='binary data in base64 encoding.', type=base64.b64decode) @cli.option('--port', help='"specify a working directory.', type=cli.File('rb')) @cli.option('--log-level', help='set the log level.', type=int) @cli.option('--detach', is_flag=True, help='detach daemon from console') def hello(**kwargs): print(kwargs) hello(["--detach", "--listener", "localhost:8080"]) I have a hard time finding the motivation to look for the truth behind your other arguments after that.
- nikofeyn 8y agothis is interesting, because if i didn't read your commentary, these examples seem to favor f#. :) what are your objections? what is the dense symbology? discriminated unions (what the CLIArguments is) are very simple to define and understand. the usage member nearly uses the simplest possible pattern matching available. pattern matching is a staple of functional languages. it's a case statement in its simplest use but is so much more in general. these two things are the bread and butter of f#. they may take a modicum more initial effort than simple function calls, but it pays off in readability and expandability. it seems python takes the easy route. it makes things apparently simple at first but difficult in the long run. i know both languages, to a degree, and find the python hard to read. it's also faking types, which is kind of funny. the f# code is fully typed. lines of code is meaningless to me here because the f# has better delineation of concepts here. and lastly, there's actually no reason why you couldn't write an f# library to behave like the python one here. that is not true the other way around. that's the power of f#'s multi-paradigm nature.
- mkl 8y agoI'm not who you replied to but I have the same reaction. The F# version doesn't even include the actual arguments, and the capitalised and underscored versions are repeated twice. There should be no need for pattern matching or discriminated unions here. The Python version doesn't seem to be faking types, but specifying constructors.
- nikofeyn 8y ago> The F# version doesn't even include the actual arguments, and the capitalised and underscored versions are repeated twice. i don’t know what you mean. actual argumennts? do you mean like “—working directory” or the values passed by them? i am actually not familiar with this library, but it seems the former is handled by the library from the discriminated union constructor names and the latter are right there in the constructors. and what do you mena there’s no need? that seems rather arbitrary. it’s a way to represent your data explicitly with types, i.e., is type-driven development. i can’t further defend this library because i have never used it, but i see no confusion here and don’t even understand the complaints. it seems to be “this is different than how i think in python, so it’s no good”.