News for hackers. Stuff that matters.
Re:Go + Services = One Goliath Project by whalesalad on Saturday December 21, 2019 @06:47PM (#21854046)
You had me nodding in agreement until the last paragraph. Functions are first class in Python. You can pass them all over the place and use them the same way you would in JS. You don’t have Lodash but frankly it’s not needed. The stdlib, functools and itertools are pretty much all you could ever ask for.
Re:Go + Services = One Goliath Project by thatswrong0 on Saturday December 21, 2019 @06:54PM (#21854087)
I think I meant the treatment of anonymous functions - lambdas are limited compared to normal functions.
Re:Go + Services = One Goliath Project by dwaltrip on Saturday December 21, 2019 @07:10PM (#21854176)
The lack of multi-line lamdas is one of my biggest gripes with python.
Re:Go + Services = One Goliath Project by whalesalad on Saturday December 21, 2019 @07:22PM (#21854232)
If you feel the need to use a multi line lambda you should be using a regular function.

This is a code smell for sure.

Re:Go + Services = One Goliath Project by staticassertion on Saturday December 21, 2019 @09:03PM (#21854651)
This is the silliest thing I see paroted. Anonymous functions are there for one offs. Sometimes a one-off is two lines. Breaking it out into a separate function is ridiculous.

You end up seeing functions declared within functions so that people can work around this limitation and it is grotesque.

Re:Go + Services = One Goliath Project by dwaltrip on Saturday December 21, 2019 @07:39PM (#21854313)
Regular functions definitions can't be used as expressions.

You are basically saying that one should never need a multi-line lambda. Obviously, I disagree.

Re:Go + Services = One Goliath Project by joshuamorton on Saturday December 21, 2019 @07:55PM (#21854383)
If you need to express something complex enough that you can't do it in a single statement in Python, it deserves to have a name (or more likely, it already has one in the standard library).
Re:Go + Services = One Goliath Project by baddox on Saturday December 21, 2019 @08:12PM (#21854444)
But python for loops can and typical do have multiple lines, yet that “block” inside the for loop doesn’t have a name. The fact that the body of a for loop can have multiple lines but an anonymous function cannot is a purely arbitrary syntax limitation, and the principle you stated ought to apply (or not apply) equally to both use cases.
Re:Go + Services = One Goliath Project by joshuamorton on Saturday December 21, 2019 @08:30PM (#21854523)
This doesn't follow: for loops are there specifically for cases of the complexity that can't be handled by other constructs (like comprehensions). Anonymous functions are not, for the complex cases you give the construct a name.

It's a very intentional language limitation, much as semantic whitespace is an intentional limitation.

And there is actually a language difference. A for loop is a statement. A lambda is an expression. Python doesn't let you put statements into expressions.

Re:Go + Services = One Goliath Project by lesserknowndan on Saturday December 21, 2019 @09:09PM (#21854678)
I tentatively disagree with both of you.

I've sometimes wondered whether code would be universally clearer if all you could do in a loop is have a one-liner or call another function/method (mainly when looking at my own code within loops and thinking WTF!!!).

Would probably cause issues when teaching programming though. It would be interesting to have a compiler switch that enforced this...

Re:Go + Services = One Goliath Project by baddox on Saturday December 21, 2019 @11:05PM (#21855111)
What comes to mind immediately is that you would lose the ability to `break` unless you had another convention like returning a specific value to indicate you want to break.
Re:Go + Services = One Goliath Project by lesserknowndan on Sunday December 22, 2019 @04:16AM (#21856098)
If you are limited to one statement you could still do something along the lines of the following (no particular language):

  foreach ( $item in $list )
  {
    if ( 1 == some_function( $item ) )
    {
      continue;
    }
    else
    if ( 2 == some_function( $item ) )
    {
      break;
    }
    else
    {
      another_function( $item );
    }
  }
But I would immediately concede that it is starting to miss the entire point of why it was enforced in the first place...
Re:Go + Services = One Goliath Project by joshuamorton on Saturday December 21, 2019 @11:36PM (#21855205)
I actually like this style (or similar if not quite as extreme). I find it's much clearer what's going on.
Re:Go + Services = One Goliath Project by dwaltrip on Saturday December 21, 2019 @08:19PM (#21854468)
Thanks for writing this, that clarifies the issue more clearly and concisely than what I had in mind.

I will mention a core aspect of my argument, to add to your point.

When you make a named function and then use it separately somewhere else, there is a loss of locality. The logic is now further from its point of use. This is a cost, and sometimes it is an unreasonable one.

Re:Go + Services = One Goliath Project by guitarbill on Saturday December 21, 2019 @08:44PM (#21854578)
i'd agree with this, except you can have a function within a function in Python to limit scope and keep it local. yeah, you have to define it before the code using it - sometimes this feels like a boon though, especially compared to huge inline lambdas. so over time, my annoyance with this has decreased, and it doesn't bother me anymore.
Re:Go + Services = One Goliath Project by threatofrain on Saturday December 21, 2019 @09:03PM (#21854655)
I've started to use Python type hints, but even with typing I like to label my names things that describe local concerns (types are often more general than what you mean to say), and sometimes I'll deliberately shorten the names to make a Python lambda fit where in another language with bracketing I'd just take an extra 1-2 lines and format the line differently.

I've written snippets or data structures one way or another as I'm sure many have, and in my experience the results have been mixed. This and the fact that reduce has no bearing on your app architecture, I do see this as arguing over a small and vague gain or loss.

Re:Go + Services = One Goliath Project by jnwatson on Saturday December 21, 2019 @08:50PM (#21854606)
Large anonymous functions are very much a thing in JavaScript.
Re:Go + Services = One Goliath Project by whalesalad on Saturday December 21, 2019 @09:08PM (#21854672)
This trend will gradually fade into the history books. Just because it’s a thing doesn’t mean it’s a good one.
Re:Go + Services = One Goliath Project by doteka on Sunday December 22, 2019 @05:14AM (#21856294)
Large anonymous functions are a thing in every modern language I can think of except python. It’s the only sensible solution in the case of functional method chaining, which is much more readable than nested comprehensions. Python just got this one wrong.
Re:Go + Services = One Goliath Project by joshuamorton on Monday December 23, 2019 @05:48PM (#21868184)
Large anonymous functions are rarely used in rust, go, python, java (streams instead), or cpp.

Streams and repeated application of short anonymous functions are a much better solution to the method chaining issue.

If js supported better streaming tools, they'd be less common in js too.

Re:Go + Services = One Goliath Project by whalesalad on Saturday December 21, 2019 @08:32PM (#21854527)
> Regular functions definitions can't be used as expressions

I’m having a difficult time understanding what you mean here. Can you offer an example?

I have never felt compelled to write a multi line lambda.

Re:Go + Services = One Goliath Project by dwaltrip on Saturday December 21, 2019 @08:53PM (#21854618)
Python can't replicate the structure of this JavaScript code:

  fooBaz(x => {
    // multiple lines of logic
  })
In python, you are forced to move the logic away from the point of usage, which means you lose some locality. This loss is sometimes not worth getting a "name" for the logic.

Of course, sometimes it is better to create a named function away from the point of usage, but I don't think that is always the case.

Re:Go + Services = One Goliath Project by namelosw on Saturday December 21, 2019 @09:15PM (#21854700)
Multi-line lambda is not code smell.

There are a lot of cases like GUI programming where you need a lot of handlers which are suitable for lambda because they don't have a good name, and should never be called manually, and often they have multi-lines of codes.

Re:Go + Services = One Goliath Project by im3w1l on Saturday December 21, 2019 @07:00PM (#21854114)
If you need more power than a lambda you would use a nested function, e.g.

    def a(n):
      def b():
        print(n)
      return b
Re:Go + Services = One Goliath Project by WoodTree on Saturday December 21, 2019 @07:14PM (#21854193)
Nesting functions like this can have a bad performance impact because functions in Python are objects. Normally, all of those function objects are instantiated once when you load the module. However nested functions will be instantiated at runtime every time their parent is called, even if they aren’t used. This cost is perceptible in hot paths.
Re:Go + Services = One Goliath Project by krallja on Saturday December 21, 2019 @09:03PM (#21854652)
A lambda also behaves this way; it’s how it captures the closure scope.
Re:Go + Services = One Goliath Project by edflsafoiewq on Saturday December 21, 2019 @07:35PM (#21854292)
Are lambdas different?
Re:Go + Services = One Goliath Project by baron816 on Saturday December 21, 2019 @08:26PM (#21854508)
I’ve never seen it create a bottle neck, have you?
Re:Go + Services = One Goliath Project by weyland108 on Saturday December 21, 2019 @08:46PM (#21854588)
It will definitely be a problem if you use JIT interpreter like pypy
Re:Go + Services = One Goliath Project by saagarjha on Saturday December 21, 2019 @07:03PM (#21854137)
That's a lot of boilerplate for a closure…
Re:Go + Services = One Goliath Project by mlyle on Saturday December 21, 2019 @07:10PM (#21854178)
The trivial lambda case is short, and you can do what the parent said if you want to do something that doesn't fit into the trivial lambda case well.
Re:Go + Services = One Goliath Project by saagarjha on Saturday December 21, 2019 @07:13PM (#21854191)
The "lambda" keyword isn't :(
Re:Go + Services = One Goliath Project by ptx on Saturday December 21, 2019 @07:31PM (#21854269)
Where's the boilerplate? "def b():" and "() => {}" are both 8 characters.

It is annoying that you have to give the function a name, though.

Re:Go + Services = One Goliath Project by aserafini on Saturday December 21, 2019 @07:55PM (#21854382)
On the one hand it’s annoying, on the other it enforces a discipline of thought in the same way that having to name variables does.
Re:Go + Services = One Goliath Project by baddox on Saturday December 21, 2019 @08:16PM (#21854458)
That’s an interesting principle, something like “a block of code that is complex enough to be written across multiple lines of code ought to be given a name,” but standard idiomatic Python already violates that principle by featuring multiple lines in the body of a for loop. The fact that the body of a for loop can be multiple lines but the “body” of a lambda cannot is an arbitrary syntax inconsistency.
Re:Go + Services = One Goliath Project by jcheng on Saturday December 21, 2019 @07:57PM (#21854389)

    def b(x):
      return x + 1
vs

    x => x + 1
Re:Go + Services = One Goliath Project by earenndil on Saturday December 21, 2019 @07:06PM (#21854156)

    def a(n):
        return lambda: print(n)
Re:Go + Services = One Goliath Project by saagarjha on Saturday December 21, 2019 @07:10PM (#21854179)
That's a couple characters over most languages I normally use. Plus lambdas have a number of strange warts and restrictions (no multi-line lambdas?) that leave me feeling that Python really dislikes traditional functional programming constructs.
Re:Go + Services = One Goliath Project by WoodTree on Saturday December 21, 2019 @07:27PM (#21854258)
Python has become less functional over time. It’s also not a particularly good OO language either. It’s really a more descriptive sort of bash that became ubiquitous despite its short comings.
Re:Go + Services = One Goliath Project by AsyncAwait on Saturday December 21, 2019 @06:50PM (#21854058)
In fact, they're first class in Go too, in fact there's fewer languages where that's not the case than is, I'd imagine.
Re:Go + Services = One Goliath Project by zeugmasyllepsis on Saturday December 21, 2019 @07:02PM (#21854134)
While functions are first class in Go, the limitations of the type system make them less ergonomic to use, I think. Without user defined generics, many of the common uses of first-class functions become a lot less convenient to use.
Re:Go + Services = One Goliath Project by hactually on Saturday December 21, 2019 @08:40PM (#21854561)
Do you have an example where that's the case?
Re:Go + Services = One Goliath Project by TheDong on Saturday December 21, 2019 @09:09PM (#21854680)
One easy example is map functions.

In typescript, if I have a bunch of "User" objects where each user has an "name" and "age" field, and I want to print a comma separated list of all those names formatted as "name -- age", it's simple. I write:

    let userNamesList = let userNames = users.map(u => `${u.name} -- ${u.age}`).join(", ")
    console.log(userNamesList).
This is possible in no small part because map is generic.

In go, to get the same level of expressiveness, I'd have to write the following stuff around it:

    func mapUsersToStrings(f func(u User) string, users []User) []string {
        result := make([]string, len(users))
        for i := 0; i < len(users); i++ {
            result = append(result, f(users[i]))
        }
    }
And after writing that boilerplate, I can finally write:

    userNamesList := strings.Join(mapUsersToStrings(func(u User) string { return fmt.Sprintf("%s -- %d", u.name, u.age) }), ", ")
That boilerplate, of having to write a specialized map/filter/etc function with a for loop for every combination of types you transform between (mapUsersToStrings, mapUsersToAddresses, mapUsersToAges) is really annoying.

It's harder to point to many other cases because, simply enough, people don't write such cases. The fact of the matter is just that go libraries make very sparing use of first-class functions because the lack of generics prevents it from working well, and so we end up with an entire language ecosystem where code is harder to read and with fewer simple abstractions reused across it.

You can still write any code without good generics or first-class functions, you'll just have more programmers writing more code with less clean abstractions.

Re:Go + Services = One Goliath Project by edflsafoiewq on Saturday December 21, 2019 @09:06PM (#21854669)
map, filter, fold, etc.
Re:Go + Services = One Goliath Project by Scarbutt on Saturday December 21, 2019 @07:13PM (#21854192)
If you add in Typescript as he said, is a much better proposition than mypy.