Hacker News new | ask | show | jobs
by jmnicolas 2498 days ago
Can someone explain me why they always (OK let's say almost always) use math formulas to show what you can do with a programming language ?

I'm a desktop application programmer, not a mathematician. I don't need to print the first 25 squares of integers or Fibonacci whatever. In fact I think the hardest math I did at work was using modulo to get even and odd numbers ...

Show me how you parse a csv file, how do you connect to webservices or retrieve data from a database, show me how to do a simple GUI, show me something useful for the common dev.

I'll judge your ultimate programming language on these menial tasks that comprise 99.9% of my programming time.

4 comments

Extracting two columns out of a excel sheet:

     (->> (d/load-workbook file "Questionnaire.xlsx")
       (d/select-sheet "Sheet1")
       (d/select-columns {:A :item :B :price}))
Now we're talking. It would probably take 20+ lines of C# to do the same thing.

How do you manage errors? What happens if Questionnaire.xlsx or Sheet1 doesn't exist ?

> How do you manage errors?

It becomes unwieldy like every other language.

> What happens if Questionnaire.xlsx or Sheet1 doesn't exist ?

Runtime exception.

I've seen too much Clojure code (and this goes for every language where error handling is optional - Hi Javascript!) just skip error handling and focus on "happy path".

And as demonised as Java's checked exceptions are, they at least forced error handling to be thought of.

Or you could use: https://github.com/adambard/failjure

Ya'll underestimate the power of a programming language to create a programming language. Just replace the arrow with `ok->>`

What is 'd'?
It's an alias given to an imported module name. In Python it might be:

  import really_long_name as rln
  rln.foo()
I know that part :) What module is it referencing?
I like the suggestion in namespace aliasing in https://stuartsierra.com/2015/05/10/clojure-namespace-aliase...:

As a general first rule, make the alias the same as the namespace name with the leading parts removed.

  (ns com.example.application
    (:require
     [clojure.java.io :as io]
     [clojure.string :as string]))
Keep enough trailing parts to make each alias unique. Did you know that namespace aliases can have dots in them?

  [clojure.data.xml :as data.xml]
  [clojure.xml :as xml]
Eliminate redundant words such as “core” and “clj” in aliases.

  [clj-http :as http]
  [clj-time.core :as time]
  [clj-time.format :as time.format]
Then you can see immediately what `d` is...

Namely:

  (require '[dk.ative.docjure.spreadsheet :as spreadsheet])
(You would still not know the library and might have to ask the same question, but it makes more sense.)

About `d`:

There are always exceptions. For example, some namespaces have established conventions for aliases:

  [datomic.api :as d]
I'm with you. Reading a text file (line by line) is the thing I do most and what I look for first. If you can't do that in a simple way, I move on. I also look at returning datasets from SQL databases, how you can make a GUI, and a host of other practical things. I think fibonnaci is a sort of one step up from "Hello World", so in a sense it gives a little taste of the language and syntax.
I think if all you are doing is reading files line by line, reading a database dataset etc, then your choice of language is probably irrelevant. Choose whatever you prefer typing.

But here's CLojres read a file line by line and print it out:

    C:\\foo.txt
    "THis is line 1
     This is line 2
     This is line 3"

     (with-open [rdr (io/reader "C:\\foo.txt")]
        (doall (map println (line-seq rdr))))
      =>THis is line 1
        This is line 2
        This is line 3
A simple function to read a specified file line by line

   (defn read-file-line-by-line [file-path]
      (with-open [rdr (io/reader file-path)]
         (doall (line-seq rdr))))

   (read-file-line-by-line "C:\\foo.txt")
   => ("THis is line 1" "This is line 2" "This is line 3")
To read the line by line and convert them to upper case

     (map clojure.string/upper-case (read-file-line-by-line "C:\\foo.txt"))
     => ("THIS IS LINE 1" "THIS IS LINE 2" "THIS IS LINE 3")
I don't think this is remotely true. Compare doing file parsing in Python, Perl, C#, Java, Common Lisp, OCaml, Ada, Fortran, C++...etc.

Doing it in Python is easy...it is a bigger pain in several of the other ones. Even your Clojure examples are definitely more work than in Python. You even defined a helper function (something I've never needed to do in Python) as the default is so easy. Mind you, the Clojure isn't too bad and definitely better than some of the others I've mentioned.

To your average developer...this is indeed probably irrelevant as IO might be a small part of your codebase. I do a lot of process automation though and do a lot of IO.

Here is an example to massage/manipulate CSV data.

Stolen from the README page for a clojure CSV parsing library (https://github.com/clojure/data.csv)

    (defn read-column [reader column-index]
      (let [data (read-csv reader)]
        (map #(nth % column-index) data)))
    
    (defn sum-second-column [filename]
      (with-open [reader (io/reader filename)]    ; Read in the CSV file (streaming / lazily)
        (->> (read-column reader 1)               ; Convert to just the first column of data.
             (drop 1)                             ; Drop the first row (the CSV header)
             (map #(Double/parseDouble %))        ; convert each string in this column into double
             (reduce + 0))))                      ; sum the result

Because it's lazy, this code should work regardless of how large the CSV file.
Using the clj-http library in clojure to fetch from a REST webservice:

    (client/get "http://example.com/resources/3" {:accept :json :query-params {"q" "foo, bar"}})
With the response, you can examine response headers, the body, etc.
What about JDBC?

Here's a few examples stolen from the doc page for the next.jdbc library (https://github.com/seancorfield/next-jdbc):

    > clj
    Clojure 1.10.1
    user=> (require '[next.jdbc :as jdbc])
    nil
    user=> (def db {:dbtype "h2" :dbname "example"})
    #'user/db
    user=> (def ds (jdbc/get-datasource db))
    #'user/ds
    user=> (jdbc/execute! ds ["
    create table address (
      id int auto_increment primary key,
      name varchar(32),
      email varchar(255)
    )"])
    [#:next.jdbc{:update-count 0}]
    user=> (jdbc/execute! ds ["
    insert into address(name,email)
      values('John Smith','john.smith@email.org')"])
    [#:next.jdbc{:update-count 1}]
    user=> (jdbc/execute! ds ["select * from address"])
    [#:ADDRESS{:ID 1, :NAME "John Smith", :EMAIL "john.smith@email.org"}]

That is an example REPL session to setup the library, setup a datasource, create a table, insert a row into the table, and then select from the table. The "user=>" part is the REPL command prompt. Essentially it's one statement for each SQL query executed, and 1 or 2 statements to setup the JDBC datasource. This is tight.

You can see the return from the select contains clojure native data-structures. It returns a list of rows, where each row is a map of fieldName to fieldValue. You can now go to town and manipulate lists and maps to your hearts content, convert the payload to HTML or JSON or whatever you like.

I'd read the crap of an article that summarizes how any 10 languages handle these general purpose tasks.
Check out Rosetta Code: https://rosettacode.org/wiki/CSV_data_manipulation

It's a wiki, not a blog, but I've lost countless hours browsing through it and trying stuff out for myself.