Hacker Newsnew | past | comments | ask | show | jobs | submit | spqr233's commentslogin

This is really interesting! I use github actions almost entirely so I wonder if it'd be possible to integrate it with that CI system.

Taking a step back, if you want to see this become more widely useable I'd suggest finding ways to integrate to existing workflows.


Yes, I have been taking a look at https://github.com/nektos/act which allows running github actions workflow locally. I am investigating if I can integrate it directly in togomak, so that users can reuse existing github action in their pipeline. For the most bit, these pipelines run in node docker containers. I'm hoping to add a concept called "operator" where you can specify or use multiple build backends like Google Cloud Build, or GitHub Actions.


I don't the author really gave Ocaml a chance. He argues that every language needs to have interfaces. I agree somewhat with that statement, but I think the truer statement is to say that every language needs to have some way of defining composition at a structural level.

An interface allows you to pass different "structures" to the same function so long as they adhere to the same spec. In Ocaml this is accomplished through modules, functors, and module signatures. Ocaml's module signature can play the same exact role as interfaces in Haskell, Rust or F#.

The module system is arguably more expressive than what can be accomplished to interfaces. To give an example, Ocaml suffers from the same problem as rust does with having two standard implementations of a async runtime. Just like rusts: tokio and async-std, ocaml has Lwt, Async, (and newly added to the mix Eio).

Whereas in rust most libraries just implement one of these systems, and you'll have to use compiler directives to support both. Ocaml's module system means that you can describe the async runtime as a signature and make your entire library generic to the async runtime it runs on top of. Most of the well-used libraries do this, and so you don't have to worry too much about which runtime you decide to use.

Clearly, a language that can do that must have in some place a system that can replace interfaces.


Politely, I feel like this is the issue with OCaml as a community. You gave a beautiful answer about programming language design and composition. But how does it feel to write the language? How can you print a user defined data type? From reading around, it seems like your options are: explicitly pass a print function for that specific type, use a third party library for printing, or (my "favorite") don't. Or how does it feel to write a function that takes a generic that can be printed, checked for equality, and read? Or to convert one type into another type?

And we're still talking about semantics here. How does it feel to use the language server? How does it feel to read the code? To build the language? Ultimately that's what users judge a language on. Yes, Rust in some ways has a worse form of abstraction. It is global, not fully generic and doesn't allow for overloading. But it creates a user experience that is nicer. It lets a user print something and compare two variables and do type conversions without having to scratch their head, read a forum post and import a library.


> You gave a beautiful answer about programming language

You do the same thing as in Rust, Scala or Haskell and derive the printer [1]. Then at the callsite, if you know the type then you do `T.show` to print it or `T.eq`. If you don't know the type, then you pass it in at the top level as a module and then do `T.show` or `T.eq`.

> Or to convert one type into another type?

If you want to convert a type, then you have a type that you want to convert from such as foo and bar, then you do `Foo.to_bar value`.

We can keep going, but you can get the point.

You _can't_ judge a language by doing what you want to do with one language in another. If I judge Rust by writing recursive data structures and complaining about performance and verbosity that's not particularly fair correct? I can't say that Dart is terrible for desktop because I can't use chrome developer tools on its canvas output and ignore it's hot-reloading server. I can't say Common Lisp code is unreadable because I don't have type annotations and ignore the REPL for introspection.

[1] https://github.com/ocaml-ppx/ppx_deriving


Okay...so you have to add a third party library to print? Yes, recursive data structures are a pain in Rust (well, recursive multi-owner data structures). But that's like comparing changing your oil to opening your car door. We do one of these a lot more. And bear in mind, I had to find this answer by googling and reading a random forum post. That's some pretty poor documentation.

And that's not talking about aesthetics. `T.show foo` or `Foo.to_bar value` is a lot of syntactic overhead for a rather common task.

And again, these are the lesser concerns to the other ones I outlined. Reading the code, building the code, and understanding the compiler errors are the big ones.


Not really third-party; ocaml-ppx is something similar to `javax` in the Java space? But it is optional and doesn't come bundled with OCaml.

Recursive structures are only rare in Rust _because_ they suck to write and have terrible performance characteristics in the language. In languages like Haskell, OCaml and Scala using tagless initial encodings for eDSL's [2] are really, really common.

I don't write Rust like I write any semi-functional language with function composition because, well, it's _painful_ and not a good fit for the language.

> `T.show foo` or `Foo.to_bar value` is a lot of syntactic overhead

The `T.()` opens a scope so OCaml code generally looks like:

``` let foo = T.(if equal zero x then show x else "not here") ```

for,

``` fn foo(t: T) -> String { if(t == T::ZERO) { t.show() } else { "not here".into() } } ```

Even when talking about usage, each language community for better or worse has a predefined workflow in mind. Your questions and workflow are specific to a particular language; you don't, for example, ask about the REPL, the compile times, debugging macros, the cold-start of the compiler, whether hot-reloading is a thing, the debugger, how it interacts with perf, how to instrument an application. Presumably because the language you use or the programs that you make don't have those components as part of their main workflow.

[1] https://github.com/ocaml-ppx [2] https://peddie.github.io/encodings/encodings-text.html


A lot of these things that you mentioned are valid flaws in Rust. I'm not going to dismiss them as not important or non-problems because they are genuine issues. Compile times suck. We could use hot reloading and a REPL. Debugging macros, instrumentation and perf stuff is good, but I assume it could be better. That's what I expect from a language community. Not constant denial about the state of usability. And it really does feel like many of the smaller language communities fall into this hive-mind where type signatures are valid documentation and who needs to use an editor other than emacs?


They are genuine issues, within Rust, but the way you /categorize/ the severity of the issue is different within language communities. They don't impact usability /much/ because of Rust's community, focus, size and niche.

Compile times in Rust are a problem, but the RLS does a good enough job of feedback and the development loop happens enough in compile time, that users don't miss it enough, compared to, say, Java which relies heavily on runtime behaviour/reflection for application behaviour.

Debugging token macros could be better, such as with a better macro-stepper, but you don't write enough macros in Rust to care heavily about it to make it a big deal, unlike in a Lisp.

Hot reloading would be nice, but not and ~essential~ part of development and deployment like in BEAM. Better reflection utilities might be nice but I doubt Rust libraries will ever be heavily dependent on it in the same way that Go or Java are.


If you are referring to OCaml, many people in the community care a lot about writing good documentation so that it's not just the type signatures. In fact the OCaml website team have made amazing leaps and strides integrating package documentation directly in the website.

And the experience using OCaml LSP Server with VSCode nowadays is honestly pretty good--type annotations displayed, error messages, go to definition, generating interface files. The core functionality is all there.


That's good to hear! I don't mean to be too negative. I'm genuinely glad that OCaml is making these strides. I'm hopeful that OCaml can find its equivalent of Esteban Küber[1] and they can make the language a truly fun and friendly experience.

[1]: https://www.youtube.com/watch?v=Z6X7Ada0ugE


You don't need a third-party library to derive a pretty-printer for your types, it just makes it simpler. OCaml takes the approach that the core compiler doesn't do any codegen, that is left to PPXs (basically, middlewares which transform code) which run before the compiler.

You can write a pretty-printer yourself using the conventions of the `Format` module. Is it manual and annoying? Yeah. That's why the PPX exists. It's a tradeoff.


> `T.show foo` or `Foo.to_bar value` is a lot of syntactic overhead for a rather common task.

A lot of syntactic overhead sounds like a stretch. I suppose you could drop the `T` like you do in Haskell but I personally like my language to be a bit more explicit. It improves readability.


People have to realize that printing is the least of your concern. Visible representation is not solving problem.


Scala is probably not a good example because if you need some quick and dirty printing you can override toString and keep the rest of the generic code intact. In OCaml, Rust and Haskell you would have to add type constraints in a bunch of places to make println! T.to_string and show work.


> How can you print a user defined data type?

Pretty much the same way you'd do in Haskell or Rust: you add a `[@@deriving show]` directive to your datatype.


Came here to make this exact point. But I totally agree with all of his other complaints. It’s a good list of the cons, but ignored the many pros


To me it seems he gave it a lot of chance in order to find this many problems.

It does sound to me like you stopped reading after the first point. Maybe you didn't give the post a chance?


To be honest, anyone who used Ocaml understands immediately that the author gave it no chance and went looking for problems. It’s obvious because the post lingers a lot about things which are not actually issues like type conversion but don’t talk about the very real issues Ocaml has (opam is not great, dune is weird).


Why are these things not issues? I think it's totally valid for someone who doesn't understand OCaml to raise issues of usability or documentation. It's not just the issues of experts that are a concern. And it's very demoralizing to get a "you're holding it wrong" response to a complaint.


Because they are not issues on a day to day basis when you use the language.

I used Ocaml for a paid internship some years ago. I was very much a beginner. Do you know how many time I felt at loss or annoyed by type conversion or the precedence rules for various part of the syntax? I never did.

The truth is you never encounter the precedence rules when writing Ocaml normally using parentheses like a normal human being and you don’t convert that much between exotic types. Most of the conversion you actually do are between the same types and most of the time you have to write converter anyway because there is logic involved. I worked professionally as a Java developer for a bit. I think I had to write more conversion code between weird classes then than I ever did in Ocaml.

The issue is not telling people they are "holding it wrong". The issue is that this is not what’s going to annoy you as an Ocaml beginner.

The author of this article is not even an Ocaml beginner by the way. That’s actually someone who used to work on the Haskell compiler.


> The issue is that this is not what’s going to annoy you as an Ocaml beginner.

Sure, but tbf, the post is about what annoys the author, not what would annoy beginners. As you say, the author is not a beginner, and so their problems wouldn't be beginner problems.


That’s not the point I was making. They are not expert problems either. How often as an expert do you think you encounter precedence issues you were not encountering as a beginner?


> Because they are not issues on a day to day basis when you use the language.

They still are. You just internalize them. Progammers are the world's greatest masochists with the world's biggest Stockholm syndromes, and we don't like to admit it.

For example, his pain points about syntax ambiguity are absolutely valid, and true. However, when you "use the language every day" you learn to avoid those constructs and extract them into separate functions for example because "that's how it's always done, and it's a nice little quirk of the language".


No, the syntax parts he criticises are not this kind (they are not ambiguous by the way). What’s in the article is very unidiomatic OCaml incorrectly intended purposefully to make it look like it’s doing something else than what it does.

You don’t write tuples without parentheses because it’s weird, harder to read and no one does it. Same for the precedence rules of expression. You just use begin and end for blocks like you would use braces in C because you actually want to write a block. No one is just randomly writing nested code without them because well it doesn’t work.

It’s not a quirk. The author is just complaining that you have to mark blocks like in every language. That’s a weird thing to complain about.

I agree that the lack of as-hoc polymorphism is a downside (I don’t agree with how the article presents it but the article is disingenuous from the start anyway). Everyone would like to have modular implicit.


> unidiomatic OCaml

> You don’t write tuples without parentheses

> Same for the precedence rules of expression. You just use begin and end for blocks

This is exactly what I wrote, but in a Stockholm-syndrome-y way.

> The author is just complaining that you have to mark blocks like in every language.

He points out a real ambiguity in the syntax where the parser literally parses the same-looking and same-behaving statements completely differently.

Sure it's solved by "you just write begin-end" workaround that you internalise. Or it could be solved at the syntax level (like erlang and elixir)


> This is exactly what I wrote, but in a Stockholm-syndrome-y way.

Do you complain about having to put braces around C expressions to not get unexpected behaviour from the compiler?

> He points out a real ambiguity in the syntax where the parser literally parses the same-looking and same-behaving statements completely differently.

No, he doesn’t. If that what you got from the article, you were bamboozled. He points out that match, try and (;) have different precedence which is not ambiguous. Writing begin and end is not a workaround. That’s how you mark blocks which is what he should have done because, well, he wants a block.

Erlang has exactly the same issue if you write unidiomatic code by the way.

That’s unsurprising because "don’t write code implicitly relying on precedence behaviour" is taught to virtually all beginners in most programming languages.


If you shouldn't write code that way then it should be a compilation error (or at the very least a warning) to write code that way.


I’m not sure I agree.

It’s perfectly legitimate code and working code. It’s just hard to read.

Should language prevents you from writing hard to read code if it means making trade off? I personally think that’s what linters are for but you are free to disagree.

I’m going to bed and don’t think I will revisit this comment thread. It’s probably the longest discussion I ever had about syntax points you don’t even encounter while using the language.

I have fond memory of writing OCaml. It’s nice to use. It gets out of your way. The compiler is quick. It gives nice error message. The syntax and semantics are flexible enough and elegant enough than you don’t feel like your fighting the language and your code feels nice. That’s what matters to me at the end of the day.


Is there ANY common language without TONS of ways to write bad code?

Is there ANY such language at all regardless of popularity?


It's a spectrum. Most languages have some ways to write bad code, but there are definitely languages that have more or fewer ways compared to other languages. E.g. languages with simpler precedence rules, like Lisp or TCL, avoid this particular issue because you just can't write code with unintuitive precedence (although in the case of Lisp people often end up writing a macro that recapitulates the problem).


It sounds like it's weird and annoying to convert a value to a string. That's pretty damning. Did I misunderstand?


If Ocaml fixes this and makes opam/dune play in the same field as cargo, life would be great as an ocaml programmer.

Sometimes I go back to F# and sigh because I can just print any complex data structure. Sure, there’re limits, but it’s just one less pain.

Regardless, really enjoy everything else. I cloned and built the Dune repo to try to help fix something. Compiled very quickly for its size.


Primitive conversions are as simple as `<type>_of_<newType>(myValue)`. For example, `int_of_float(2.0)` will give you an integer. `string_of_int(123)` will return a string. Noting very surprising.

If you want to do more complex conversions, you have to write those functions and call them.

I don't much care for Ocaml syntax (StandardML is a better language in basically every way and ReasonML is Ocaml with better syntax), but this isn't a big deal.


That's terrible though. How can that possibly work if the type is not hardcoded? How can you write code that works on any type like that?


The type system will know if you don't handle a potential conversion.

This restriction is better for pretty much every real-world use case anyway.

If you don't know what you're converting, then you are almost guaranteed to be getting garbage out the other end. If you do know what you are converting, being explicit and covering all your options isn't a big deal.

And of course, you can pack this all away in a module if you really want too. Modules are more flexible than typeclasses in a language like Haskell anyway (as you can't have multiple typeclass definitions in Haskell).

In truth, I believe module typeclasses (typeclasses only definable in modules) would be a nice addition. It would allow flexibility while creating a pattern that actively discourages the abuse you see in Haskell where typeclasses quickly devolve into unreadable garbage.


I've been using opam and dune for a few years now and they haven't annoyed me much since I got used to how to set up projects. What are the issues with them?


It's more that only really strongly disagreed with that point. Frankly, there are some cons with using Ocaml. In practice, I think the library support for ocaml isn't completely there given the small community.


> Ocaml's module system means that you can describe the async runtime as a signature and make your entire library generic to the async runtime it runs on top of

Is this the program describing the interface it expects, and the compiler matching that with the implementations structure (e.g. Go interfaces, Python Protocols), or is it something someone declares and the libraries implement?


Mostly the former. The compiler infers the type of the implementation and ensures it conforms to the interface. But, you can further restrict the interface's type to hide details from the outside world.


> Ocaml's module system means that you can describe the async runtime as a signature and make your entire library generic to the async runtime it runs on top of

So ... can you ELI5 to me how that is different from how you can for instance compile a C program against different libc implementations?


I mean…you can technically have a function that take void* and return void* be the interface. But you wouldn’t be able to represent things like iterator and chain them together without care. In C you would be tripping all over the slight details like forgetting to check errno or something.


So, it's like C++20 then?


Just paste the job post and your resume or LinkedIn, and get a tailored cover letter in minutes. Excited to hear your feedback and suggestions to improve it—try it out and land your dream job!


A better thing to do is take the job description and a detailed resume, and rewrite the resume to fit the job description. Cover letters might be needed in certain jobs like academia, but they have fallen out of fashion in the online application world.


An example on the landing page would be nice


Yeah I noticed I wasn't the only one with this idea either :)

It's using text-davinci-3 mostly because I was too lazy to move to gpt-3.5-turbo since that required moving to the chat api. I'll probably make the move if people use this tool enough that I'm worried about the bill from openai.

- It being impressively fast comes from me using the streaming API. That's actually where I spent most of my effort making work. OpenAI sends their messages via SSE to my server which then instantly streams that also by SSE to the browser client. It turns out this is hard to make work because most reverse proxies want to buffer responses so you have to figure out the configuration to make sure your responses aren't buffered.

- The candidate name link problem comes from the fact that I translate GPT3's output as markdown so [Candidate Name] turns into a link to nothing (I'm gonna go and change that soon I swear).


What I've noticed is that it's optional for most places I applied to. There was this time where I applied to a startup and added a cover letter. The interviewer remembered of me as "the guy who wrote a cover letter".

That made me realize that since most people aren't doing it, a cover letter would help me standout. Seeing a cover letter is rare enough that people value it more. Nowadays, I make one for any role I'm very excited about.


this is neat, what did you use to build it?


Wow that's a game changer


I think saying that Option types are different from nullable types is not true. They differ at the semantic level, around how you can interact with them (one requires you to case on whether or not the value is there, the other requires you to do that with an if statement), but at the type level the describe the same construct.

I think saying something is not the same as something else, when evidently the difference can to reduced down to syntactic sugar is a bad way categorizing and differentiating types.


The article mentions unions vs discriminated unions and then mentions nesting nullable being different than nesting optional, but it doesn't really tie the knot.

Imagine (sorry for pseudocode):

  type Option T = Some T | None
  type Nullable T = T | null
The difference here is that Option "tags" each part of its union, which guarantees that the parts are disjoint. In Nullable, the parts of the union are disjoint only if T is not itself nullable. If T is S | null, Nullable T is S | null | null, which is just S | null (since null and null are not disjoint.


I think I'd put it even more on the syntax. Option requires you to explicitly deal with the fact that it is an Option. For nullable types, frequently the syntax doesn't require you to acknowledge that it is nullable at all, and will allow you to continue forward on the assumption that the object doesn't contain null.


Why is it getting upvoted? Seems suspicious


Well... yes. But obviously to some limit. I don't think the US could extradite someone over matters that don't involve the something in the country.


Correct me if I am wrong, but I think US claims jurisdiction over anything that involves a transaction in USD. And because of the way international payment systems are set up, there always is a USD transaction somewhere in the loop.

If a Danish customer takes his Danish Krones to the bank and sends them to a supplier in Germany in the form on Euros, the transaction goes like DKK → USD → EUR, so US claims jurisdiction over it and enforces its domestic laws on it:

https://www.icenews.is/2012/03/04/us-confiscates-policemans-...

And it doesn't even have to be an international transaction. Even domestic ones sometime run afoul of this limitation, as this Canadian small business owner found out:

https://www.cbc.ca/news/canada/toronto/square-canada-1.53031...


Sounds and read more like an very rare case where it is not even clear if this holds up in court.


Not really. This is how US is able to unilaterally impose sanctions on Iran. Since international transactions go through USD, they have effectively cut Iran from being able to transact with the rest of the world on a meaningful scale. European countries tried to build an alternative to circumvent the need for a USD layer, but it has not been successful. USD's unique position in the international stage allows US to impose its domestic policy on a large part of the world. From Washington Post:

> The power of U.S. sanctions lies in the use of the U.S. dollar in most international transactions. A foreign company that sends its proceeds from trade with Iran through an international bank would likely face sanctions because part of it would be conducted in dollars. An international company with an American employee who has something to do with a transaction, no matter how inconsequential, could also run afoul of U.S. sanctions.

https://www.washingtonpost.com/world/national-security/iran-...


I have heard of this exact thing, but can't find the information about it. I think it was a Matt Levine article?.

I'm so hazy on the details, other than that French nationals were prosecuted for alleged crimes in France because those crimes were denominated in US currency.

Edit: My memory must be wrong - there's a comment below that France will not extradite citizens


>But obviously to some limit

The only actual limit is if you hide in Russia or China.


I've read that France will not extradite a French citizen. So that's one other place to hide, if you're a French citizen. You won't escape justice that way, I think - if necessary they'll try you in France for a murder you committed in the US - but you'll escape US justice.


I couldn't believe that so I read up on it.

And indeed, https://www.foxbusiness.com/markets/french-law-prohibits-ext... claims that French law says that France will not extradite its own citizens. And they have written that into every treaty they sign. For example http://www.mcnabbassociates.com/France%20International%20Ext... is the treaty with the USA and it includes:

Article 3(1) declares that neither State has an obligation to extradite its own nationals, but the executive authority of the United States shall have the discretion to do so. The nationality of the person sought shall be the nationality of the person at the time the offense was committed.

Article 3(2) requires a State that refuses an extradition request solely on the basis of the nationality of the person sought to submit the case to its authorities for prosecution, if so requested by the Requesting State.

It appears that you are entirely correct!


However, France is also subject to the European Arrest Warrant, which means they are "precluded from refusing the surrender of their own nationals wanted for the purposes of prosecution, but they may condition the surrender of a requested person on his or her being returned to the issuing state to serve any sentence ultimately imposed". This is obviously only for other European countries, but I bet you could then extradite from such a country to extra-EU jurisdictions simply with political help.

So let's say person X is wanted in the US. They get Country A to emit a warrant for them, A gets X from France, then extradites X to the US.


An example would be Roman Polanski who fled to France while awaiting sentencing in the US.

Also I think Germany will only extradite to EU countries.


Italy will also refuse extradition depending on the charges. Capital punishment for minors has been a sticky subject for several countries.


If you make good movies, France is fine with you raping minors in USA.


They would let you in just to spite the US.


Where is copyright infringement located?


In every so-called "free trade" agreement.


I'd doubt he would be extradited if he was in his country of citizenship


I am from Brazil...

During cold war, any kind of suspected "socialism" seemly counted as "something to do with USA" because a bunch of people were thrown out of helicopters (literally) when they couldn't be extradited.


Same for all Operation Condor countries.

It is a trick to avoid prosecution. When no body is found, it is hard to prove the person is dead and therefore hard to prosecute the perpetrators of the murder.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: