It feels like anything is mowed down on the internet. I’ve been a dev for a long time too, and I never feel sure when I chose a stack for a new toy project (in my day job I rarely get to chose, so that’s a non issue there)

89 points

There is a good quote from Bjarne Stroustrup for that “There are only two kinds of languages: the ones people complain about and the ones nobody uses”. I think for hobby projects it’s the best to use languages that interest you

permalink
report
reply
8 points

There are two types of programmers, those who write buggy code and those who never do anything.

permalink
report
parent
reply
1 point

This for sure. At work (fe dev), I need to get things done quickly and reliably, so I use Svelte. At home, I’m just playing around, so I’ll try things that are out of my wheelhouse or strange, eg rn I’m rebuilding the site I always rebuild in Qwik, Go, and Surrealdb - why? Because they seem neat. (Though I might just rm rf that to build something on Bun, because is there anything is can’t do?)

permalink
report
parent
reply
41 points
*

There are only two kinds of languages: the ones people complain about and the ones nobody uses. - Bjarne Stroustrup

I think people criticise every language. I’ve generally got 5 languages that I use personally and for work: Rust, Go, Python, JS, PHP. I can complain about all 5 of them at the drop of a hat. No one likes everything about any language.

permalink
report
reply
33 points

Haskell, because nobody knows haskell

permalink
report
reply
6 points

Unfortunately, no one can be told what a monad is. You have to see it for yourself (then you won’t be able to explain it to anyone)

permalink
report
parent
reply
8 points
*

The problem is people constantly try to explain it using some kind of real world comparison to make it easier to visualize (“it’s a value in a context”, “it encodes side effects”, “it’s a way to do I/O”, “it’s just flatmap”, “it’s a burrito”), when all it really is is an abstraction. A very, very general abstraction that still turns out to be really useful, which is why we gave it the cryptic name “monad” because it’s difficult to find a name for it that can be linked to something concrete simply because of how abstract it is. It really is just an interface with 2 key functions: (for a monad M)

- wrap: (x: T) => M[T] // wraps a value
- bind: (f: (y: T) => M[U], x: M[T]) => M[U] // unwraps the value in x, potentially doing something with it in the process, passes it to f which should return a wrapped value again somehow, and returns what f returns

Anything that you can possibly find a set of functions for that fits this interface and adheres to the rules described by someone else in this thread is a monad. And it’s useful because, just like any other abstraction, if you identify that this pattern can apply to your type M and you implement the interface, then suddenly a ton of operations that work for any monad will also work for your type. One example is the coroutine transformation (async/await) that is an extremely popular solution to the Node.JS “callback hell” problem that used to exist, and which we call do-notation in Haskell:

// instead of
const getPostAuthorName = foo => getPost(foo).then(post => getUser(post.authorId)).then(user => user.username)

// you can do this
const getPostAuthorName = async foo => {
  const post = await getPost(foo)
  const user = await getUser(post.authorId)
  return user.username
}

This is a transformation you can actually do with any monad. In this case Promise.resolve is an implementation of wrap, and then is an implementation of bind (more or less, it slightly degenerate due to accepting unwrapped return values from f). Sadly it was not implemented generally in JS and they only implemented the transform specifically for Promises. It’s sad because many people say they hate monads because they’re complex, but then heap praise on Promises and async/await which is just one limited implementation of a monad. You may have noticed that generators with yield syntax are very similar to async/await. That’s because it’s the exact same transformation for another specific monad, namely generators. List comprehensions are another common implementation where this transform is useful:

// instead of
const results = []
for (const x of xs) {
  for (const y of ys) {
    results.push({ x, y })
  }
}

// you could have
const results = do {
  const x = yield xs
  const y = yield ys
  return wrap({ x, y })
}

Another (slightly broken) implementation of monads and the coroutine transform people use without knowing it is “hooks” in the React framework (though they refuse to admit it in order to not confuse beginners).

Fuck… I actually just wanted to write a short reply to the parent comment and devolved into writing a Monad Tutorial…

permalink
report
parent
reply
1 point
*

Thought I’d finish the Monad Tutorial since I stopped midway…

The general notion that the abstraction actually captures is the notion of dependency, the idea that an instance x of your type can be in some common operation dependent on other instances of your type. This common operation is captured in bind. For Promises for example, the common operation is “resolving”. In my first post, for the getPostAuthorName promise to resolve, you first need to resolve getPost, and then you need to resolve getUser.

It also captures the idea that the set of dependencies of your x is not fixed, but can be dynamically extended based on the result of the operation on previous dependencies, e.g.:

const getPostAuthorName = async foo => {
  const post = await getPost(foo)
  if (post === undefined) return undefined
  const user = await getUser(post.authorId)
  return user.username
}

In this case, getPostAuthorName is not dependent on getUser if getPost already resolved to undefined. This naturally induces an extra order in your dependents. While some are independent and could theoretically be processed in parallel, the mere existence of others is dependent on each other and they cannot be processed in parallel. Thus the abstraction inherently induces a notion of sequentiality.

An even more general sister of Monad, Applicative, does away with this second notion of a dynamic set and requires the set of dependents to be fixed. This loses some programmer flexibility, but gains the ability to process all dependents in parallel.

permalink
report
parent
reply
5 points

Isn’t a monad just a monoid in the category of endofunctors?

permalink
report
parent
reply
3 points
*
Deleted by creator
permalink
report
parent
reply
1 point

Ohhhh, this site is a great find. Exploring all the articles right now. Thanks!

permalink
report
parent
reply
1 point
*

If you use JavaScript, you’ve probably seen a monad, since Promise is a monad. Unit is Promise.resolve(), bind is Promise.then(). As required, Promise.resolve(x).then(y) === y(x) (unit forms a left identity of bind), y.then(Promise.resolve) === y (unit forms a right identity of bind), and x.then(y.then(z)) === x.then(y).then(z) (bind is essentially associative).

You even have the equivalent of Haskell’s fancy do-notation (a form of syntactic sugar to save writing unit and bind all over the place) in the form of async/await. It’s just not generalized the way it is in Haskell.

permalink
report
parent
reply
3 points

Monads 👁️👄👁️

permalink
report
parent
reply
23 points
*

Python is for some reason darling of many, sometimes it has almost religious connotations. Meanwhile differences from e.g. PHP are mostly superficial and each has their strengths and weaknesses.

Bourne shell is orders of magnitude worse clusterf*ck than JavaScript, yet it’s rarely criticized.

Rust rarely gets criticized which isn’t necessarily a problem, since it’s IMHO a good language for its intended use case. But people tend to recommend it for things where the trade offs come out negative. (apps not needing max. performance)

In general I wouldn’t follow the trends on social media, it’s all a huge groupthink, mostly focusing on (easily avoidable) warts, and ignoring strengths.

permalink
report
reply
8 points

Bourne shell is orders of magnitude worse clusterf*ck than JavaScript, yet it’s rarely criticized.

Both have their place. Bourne shell scripts are great as a container for connecting the various tools you have around - and for that kind of relatively simple script is way easier to use than something like Powershell. If you use it for something more complex you’re probably an idiot.

Same with Javascript - if you need to annoy someone with popups on a website, or have something dance around in the window it’s a great language. If you use it for something else you’re probably also an idiot.

permalink
report
parent
reply
6 points

Bourne shell is orders of magnitude worse…

PowerShell is to bash what a fighter jet is to a model airplane, but you don’t dare mention it or you’ll get chewed out.

I prefer it to python too, I must be the antichrist.

permalink
report
parent
reply
7 points
*

That’s because PowerShell blurs the line between programming language and scripting language. By accessing the entire .NET library, of course it’s going to have more features than a basic scripting language that relies on open source utilities installed on the system.

The reasons people hate it are because they hate Microsoft, it breaks from traditional shells too far, and it’s a pain in the ass to type (verbose). To use PowerShell effectively, you almost need to write full software programs. At that point, just use C#.

As for you preferring it to Python… I think you don’t know Python. I’m trying to come up with every way possible to make PowerShell sound better than Python, and I got nothing. Maybe you don’t like whitespace? I cannot understand your point of view here. Help me out

permalink
report
parent
reply
2 points

I use both ALOT professionally. I can say I prefer Python over PowerShell anyway… Except for Windows automation, where PS is actually pretty dope. Bash is okay, I’ve seen folks write shit in it that should have been done in Python, or GoLang, or literally anything else.

That being said, I won’t go near Rust, not because it’s a bad language feature wise, but my brain hurts when I try and read Rust code.

permalink
report
parent
reply
22 points
*
Deleted by creator
permalink
report
reply
7 points

Whenever I tested something that sounds great yet it is slow to get adoption I end learning a reason why it it’s not growing. It’s good to learn what the reason is before you spend a lot of time on it

permalink
report
parent
reply
5 points
*
Deleted by creator
permalink
report
parent
reply

Programming

!programming@programming.dev

Create post

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person’s post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you’re posting long videos try to add in some form of tldr for those who don’t want to watch videos

Wormhole

Follow the wormhole through a path of communities !webdev@programming.dev



Community stats

  • 2.4K

    Monthly active users

  • 1.8K

    Posts

  • 28K

    Comments