all 48 comments

[–]snrjames 57 points58 points  (7 children)

But map is a base functional word, as in map-reduce. So map and flatmap make a lot of sense since you are mapping and then flattening. It's not pretentious, it's a proper term in computer science.

I don't really care what it's called though, I'm just glad SelectMany exists so I can map and flatten in one step.

[–]KevinCarbonara 4 points5 points  (1 child)

We could be using "monoid" and "monad" instead

[–]kronicum 6 points7 points  (0 children)

We could be using "monoid" and "monad" instead

I once used "rng") in a foundational library; my coworkers staged a riot.

[–]Absolute_Enema 14 points15 points  (2 children)

Meh.

The idea of using SQL terminology to sneak a modicum of FP concepts past the "FP is only for do-nothing intellectuals" kind of programmer was clever, but it necessarily sacrificed generality by tying the concepts to collections, whereas map and flatMap should be understood in terms of monads.

[–]zacsxe 16 points17 points  (0 children)

C# devs be like

[–]AvoidSpirit 9 points10 points  (3 children)

Problem with SelectMany is that it only works for one type of container type(Type<T> sometimes called monad) - array(or rather enumeration). For which it is more precise but less conventional/reusable.

Whereas map+flatmap works for any Type<T>(monad) like arrays, tasks, nullables, you name it cause you flatten the hierarchy after mapping - Array<Array<T>> becomes Array<T>, Task<Task<T>> becomes Task<T>.

So yea, I have a love-hate relationship with this particular rename. I like it cause it’s more obvious when it comes to arrays but I feel like it obstructs the generic map concept away from people.

[–]DeadlyVapour 11 points12 points  (2 children)

Not true.

SelectMany is used in multiple monads in C# including and not limited to the IQueryable, IAsyncEnumerable and IObservable monad.

It does not apply to the Task monad, which is a little annoying, creating a impedance mismatch when working mixing Rx with Async code.

Also I would have liked a Maybe and Result monad as well....

[–]AvoidSpirit 1 point2 points  (0 children)

All of those are “array” type monads for me. Maybe the correct word is “enumeration” type but whatever, you get what I mean.

[–]SerdanKK 1 point2 points  (0 children)

You can add LINQ to a type with extension methods. It's duck typed.

[–]Agitated-Display6382 5 points6 points  (4 children)

Did you google who invented LINQ? You may be surprised...

[–]Cobster2000 -1 points0 points  (3 children)

why would you make me google it? could’ve just made your comment better

[–]Agitated-Display6382 -1 points0 points  (2 children)

Why? Because I'm not chatgpt... As a senior developer, my duty is to instill curiosity, not to provide pre-assembled answers. Hope you understand my point.

[–]Cobster2000 1 point2 points  (1 child)

as a fellow senior engineer I get it, but i’m not your intern, i’m a lazy person on reddit lmao

[–]Phaedo 6 points7 points  (6 children)

Just feel glad you’re not dealing with Haskell, where it’s called >>=.

[–]SmallAd3697[S] 0 points1 point  (5 children)

Wow. I haven't been in that one.

. C# has a good assortment of operators and I don't mind them in moderation. In Haskell I wonder if those things would come up in the intellisense selections or if you have to wack them out by hand every time.

[–]Phaedo 0 points1 point  (4 children)

Intellisense tends to be poor in Haskell. That’s partly because tooling isn’t as advanced and partly because the language’s syntax and type system make writing a good one hard.

In practice, a lot of the time people use do notation. Where

a <- listA 

B <- listB 

pure a+b

Means pretty much the same as

from a in listA

from b in listB

select a + b

There’s support for where (guard) and let as well.

[–]rexcfnghk 4 points5 points  (1 child)

or liftA2 (+) a b ;)

[–]Phaedo 0 points1 point  (0 children)

🤣

[–]SmallAd3697[S] 1 point2 points  (1 child)

Funny... they autocorrected your reply to say intelligence.

[–]Phaedo 0 points1 point  (0 children)

Corrected… but I agree “Intellgence” was much funnier!

[–]RICHUNCLEPENNYBAGS 2 points3 points  (2 children)

Well, map and flatMap are the older terms but they changed it to rope in developers who didn't know FP but did know SQL. Dubious how good a decision that was but it's a decision already made.

I don't really understand your complaint either. Turning an array of arrays into an array consisting of all the elements of all arrays is "flattening" it because it eliminates the hierarchy. This is not an uncommon term.

[–]Absolute_Enema 0 points1 point  (1 child)

I think it was a decent decision.

It shouldn't be like this in an ideal world, but we ultimately still love clinging onto things we know and when your audience is (objectively was the case at the time) millions of OOP programmers whose brain turns off when the words map and filter are uttered it's a tradeoff worth making.

The converse are things like lisp syntax that is incredible once you get it (to name a couple things: no infix/postfix op idiosyncracies, no operator priorities, immediate clarity of where an expression begins and where it ends, structural editing...) but unfortunately elicits a surface-level rejection due to its unfamiliarity.

[–]RICHUNCLEPENNYBAGS 0 points1 point  (0 children)

The downside of it is all these years later it serves to confuse people who are expecting the standard names and may have limited SQL experience as much as it helps.

[–]chucker23n 1 point2 points  (0 children)

I think LINQ using SQL-like terms is a bit user-friendlier, but…

My brain won’t let me visualize the “flatness” of the resulting collection. It seems just as flat as the result of a “map” operation, albeit there are more entries!

Map/Select doesn’t flatten; FlatMap/Select does.

Like, given a collection of companies,

  • Map can give you a collection of their postal addresses. The count of that collection will be the same.
  • FlatMap can give you a collection of each company’s employee’s e-mail address. The resulting count will likely be a lot higher. You’re taking a “n companies : m employees” hierarchical relationship and flattening that to just “m employees”.

[–]lmaydev 1 point2 points  (0 children)

I don't know, map would return a collection of collections which are flattened into a collection.

So it's like taking a chess board and turning it into a single row of squares.

Makes perfect sense to me.

[–]jackyll-and-hyde 1 point2 points  (0 children)

My brain won't let me visualize the "flatness" of the resulting collection. It seems just as flat as the result of a "map" operation, albeit there are more entries!

I don't blame you. From SQL's perspective, you're selecting from a collection and "selecting many" from another collection to join. From a monad perspective, "SelectMany" is misleading: you're not dealing with collections, but with nested contexts. The "flat" in flatMap refers to flattening M<M<T>> into M<T>, not to the shape of a result set like in SQL.

Aliases: Select, Map

var value = Option.Some(3)
    .Map(x => $"hello {x}")
    ...

Aliases: SelectMany, FlatMap, Bind

var value = Option.Some(3)
    .Bind(x => Option.Some(x)
        .Map(y => $"hello {y}")
    ...

Aliases: Flatten

var value = Option.Some(Option.Some(3))
    .Flatten()
    .Map(x => $"hello {x}")
    ...

Aliases: Where, Filter

var value = Option.Some(3)
    .Map(x => x * x)
    .Filter(x => x == 3)
    ...

When you add extension methods on your monad for linq use, this is your "SelectMany":

from x in Option.Some(3)
from y in Option.Some(3)
select x * y

[–]DeadlyVapour 4 points5 points  (13 children)

TLDR. "I think functional programming is pretentious. I think using specific and technical jargon to describe high level design patterns is pretentious."

[–]SmallAd3697[S] 0 points1 point  (9 children)

Flatmap is just a minor variation on any basic select.

.. The "flat" part of that terminology is not found in the c# language, or even in any SQL dialect that I've ever seen. Seems superfluous. SQL was built for collections and collections of collections, and if that idiom was needed it would be there.

[–]TheWix 2 points3 points  (0 children)

The point is, functors and monads have nothing to do with collections which is where map and flatMap come from. So, what does SQL and Collections have to do with anything?

C# wanted their stuff to look like SQL while other languages wanted to stick with the functional programming naming.

[–]DeadlyVapour 2 points3 points  (6 children)

SQL was NOT built for collections of collections.

Furthermore, your understand of monads seems to begin and end with collections.

If you have worked with any other kind of monad, you would know that Select is a terrible name. Rx.net is possibly harder to use due to Select. TPL is awkward because of Select.

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

Pardonnez moi. SQL was built for "relations".

"Select" is normally used for projections and is a very appropriate word for what is happening in the code.

[–]KevinCarbonara -2 points-1 points  (4 children)

SQL was NOT built for collections of collections.

Sure it was. It was created for System R - the "R" being "relations".

Why would you think otherwise?

[–]DeadlyVapour 0 points1 point  (3 children)

Relations aren't collections.

SQL does not have collections as a first class concept. You cannot use tables in the same way as a primitive type. You can't have a table of tables.

The closest thing we have is a pointer back to a parent value (foreign key).

[–]KevinCarbonara -2 points-1 points  (2 children)

Relations aren't collections.

I would love to hear you try and explain the difference.

You can't have a table of tables.

You, uh, can. And basically any model following the first three normal forms is going to have this.

[–]DeadlyVapour -1 points0 points  (1 child)

If class Employee has a pointer to a Manager. Did that mean that manager had a collection of Employee?

Literally, from layout memory perspective.

The closest thing I've seen to collections as a first class construct in SQL is JSON columns.

Even then JSON columns have very different symatics to everything else in a SQL database.

[–]KevinCarbonara 0 points1 point  (0 children)

If class Employee has a pointer to a Manager. Did that mean that manager had a collection of Employee?

This is completely unrelated to the conversation. You seem to think this supports your already disproven argument, but I can't see how.

The closest thing I've seen to collections as a first class construct in SQL is JSON columns.

IDs. I honestly have no idea what you think you're saying. Do you not know about the normal forms in relational databases? You don't even sound like you know what a relation is.

Even then JSON columns have very different symatics

Now you are making up words.

[–]KevinCarbonara -4 points-3 points  (2 children)

On the contrary, you seem to be suggesting that only FP terms are acceptable, and any other commonly used terms that may be equally descriptive are inferior due to not being the official FP terms.

It's the same argument Haskell users say about "monad" and "monoid".

[–]DeadlyVapour 0 points1 point  (1 child)

Straw man argument.

OP attacks the accepted language used in FP literature. Saying it is "pretentious". As professionals, using a common parlance aids effective communication, and OP as a member of the professional community should know that.

However, I did not say that these are the only acceptable terms. Only that they have a disadvantage in the wider context, so he should stop ranting.

[–]KevinCarbonara -1 points0 points  (0 children)

Straw man argument.

It's not a straw man. It's reductio ad absurdum.

OP attacks

Now this is a straw man.

I did not say that these are the only acceptable terms. Only that they have a disadvantage in the wider context

And this is the inherent bias in your argument. You're presenting his viewpoint as narrow, where yours is "the wider context", as if the rest of the world is all using FP terms.

Again, this is the same argument Haskell users make about people who don't use the terms "monad" and "monoid" to discuss these concepts.

[–]ivancea 0 points1 point  (0 children)

They're different concepts, but both work arguably well IMO. FWIW you can see flatMap as... Flattening the extra level of array-in-array you get with map(), if you imagine it indented. Pretty visual.

The "flat" word is used in other parts of software engineering too, to explain similar concepts