I hate Scala


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    Fucking Retarder Feature of the Day: scanLeft.

    The concept itself is very sensible: there's some accumulator that holds state between iterations, and a mapper function that maps each element of a sequence making use of mutable state, producing new sequence.

    • The return value must be the same type as your accumulator. Why? Fuck you that's why.
    • The initial accumulator value is added at the beginning of new sequence. So scanning through an N-element sequence gives you N+1 elements. With the first element being the same regardless of what the sequence holds. I can't think of any situation where this might be useful.
    • The initial value is obligatory. This is the part that makes sense - it can't really be done otherwise, and you can always use Option with the initial value of None. What doesn't make sense is that - due to the WTF #1 - the resulting sequence of type Seq[T] now has to be of type Seq[Option[T]].
    • Using None for initial value doesn't actually work. You have to explicitly annotate the type: None: Option[ComplicatedType[(WithA, TupleInside)]]. And don't even think of using wildcard like this: None: Option[_] - yes, it's valid syntax; yes, it compiles; but it doesn't do what you want, since the type inference is non-backtracking, so None's type will get resolved to Option[Any], and your sequence loses all type information and becomes Seq[Option[Any]] - which is useless for anything except printing.

    Do you actually want the running total? If not, just use aggregate. If I'm reading your bitch fest correctly it seems like that's what you want. Or I'm confusing in TwelveBaud's response.

    For a result that's the "running total", including the initial value makes sense. It also makes sense that the result is a Seq[accType]. What other type would you want?


  • Banned

    @mikehurley I'm transforming elements of sequence A by using data stored in another sequence B of completely different type, with a variable number of elements from B used for each element of A. In Rust, my accumulator would be B, and my function would return what I want directly. Here in Scala, my accumulator is a tuple of the transformed previous element which I don't use and B which I use, and the returned value is a tuple of what I actually want, and B which I have to filter out with another mapping.

    It could be made so much more convenient for my use case while remaining just as useful for running average, if they only relaxed type constraints a little bit.


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley I'm transforming elements of sequence A by using data stored in another sequence B of completely different type, with a variable number of elements from B used for each element of A. In Rust, my accumulator would be B, and my function would return what I want directly. Here in Scala, my accumulator is a tuple of the transformed previous element which I don't use and B which I use, and the returned value is a tuple of what I actually want, and B which I have to filter out with another mapping.

    It could be made so much more convenient for my use case while remaining just as useful for running average, if they only relaxed type constraints a little bit.

    I guess I don't understand what you're doing. I would expect you'd maybe want to group or filter+map from the source seq.


  • Banned

    @mikehurley it's neither grouping nor simple filtering. I have a quite complex data type that I need to transform into slightly different complex data type. One of the steps taking some unique-but-interchangable strings from predefined pool and pairing them with objects inside array inside one of the fields of the original struct. A perfect job for leftScan. But Scala creators are being assholes to all the people using leftScan for anything else than running total, for the sake of being assholes (and maybe shortening their running total function by 3 characters, at the cost of lengthening other people's running total functions by 5).


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley it's neither grouping nor simple filtering. I have a quite complex data type that I need to transform into slightly different complex data type. One of the steps taking some unique-but-interchangable strings from predefined pool and pairing them with objects inside array inside one of the fields of the original struct. A perfect job for leftScan. But Scala creators are being assholes to all the people using leftScan for anything else than running total, for the sake of being assholes (and maybe shortening their running total function by 3 characters, at the cost of lengthening other people's running total functions by 5).

    Now you have me curious. How are you conditionally pulling in only the values you want for each "source" item? I only know about scanLeft since it comes up when you Google for aggregate type stuff.

    Would you mind posting a simplified snippet?


  • Banned

    @mikehurley ok, but in Rust because I hate Scala:

    fn main() {
        let x = vec!["i", "hate", "scala"];
        let y = x.into_iter().scan(1.., |i, s| {
            let mut r = String::from(s);
            for n in i.by_ref().take(s.len()) {
                r.push_str(&format!("-{}", n))
            }
            Some(r)
        });
        println!("{:?}", y.collect::<Vec<_>>())
    }
    

    (playground link)


  • Banned

    Side note - I checked the source code of that by_ref() method and I'm completely taken by its simplicity.

    fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
    

    That's it. The entire function's body is { self }. Literally just returning itself. And by the magic of Rust type system, it does something extremely useful. Absolutely stunning.


  • Considered Harmful

    @gąska and what would happen if you didn't have .by_ref() there?


  • Discourse touched me in a no-no place


  • Banned

    @pie_flavor said in I hate Scala:

    @gąska and what would happen if you didn't have .by_ref() there?

    take() would move iterator out of accumulator, and borrow checker would bitchCOMPLAIN about it. Instead, I take a mutable reference to the iterator so I can use combinators but leave it in place, and keep the changes in iterator's state for subsequent iterations.


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley ok, but in Rust because I hate Scala:

    fn main() {
        let x = vec!["i", "hate", "scala"];
        let y = x.into_iter().scan(1.., |i, s| {
            let mut r = String::from(s);
            for n in i.by_ref().take(s.len()) {
                r.push_str(&format!("-{}", n))
            }
            Some(r)
        });
        println!("{:?}", y.collect::<Vec<_>>())
    }
    

    (playground link)

    There's just enough Rust-ness that I don't quite follow what's going on. I know zero Rust. Looks like some awful C++ STL functions. Are you appending all the previous elements to the current element?


  • Banned

    @mikehurley maybe a pseudocode that has sigils and other Rust weirdness removed will help?

        let x = ["i", "hate", "scala"];
        let y = x.scan(1.., |i, s| { // acc = sequence from 1 to infinity, second argument is lambda taking 2 args, i and s
            let r = s;
            for n in i.take(s.len()) { // take as many ints from acc as there are letters in s
                r += "-" + n;
            }
            Some(r)
        });
        println(y)
    

    This prints ["i-1", "hate-2-3-4-5", "scala-6-7-8-9-10"].


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley maybe a pseudocode that has sigils and other Rust weirdness removed will help?

        let x = ["i", "hate", "scala"];
        let y = x.scan(1.., |i, s| { // acc = sequence from 1 to infinity, second argument is lambda taking 2 args, i and s
            let r = s;
            for n in i.take(s.len()) { // take as many ints from acc as there are letters in s
                r += "-" + n;
            }
            Some(r)
        });
        println(y)
    

    This prints ["i-1", "hate-2-3-4-5", "scala-6-7-8-9-10"].

    In scala I'd do an outer map() with an inner take()


  • Banned

    @mikehurley if I understand you correctly, you'd put the accumulator in a variable outside the expression and mutate it there? Doesn't sound very functional if you ask me - and fucks you up when you apply more combinators later on.


  • kills Dumbledore

    @dfdub said in I hate Scala:

    If you can tell me a way to enter this character via my keyboard without changing language settings, I will happily do that from now on

    @g, find @Gąska, move the cursor back to delete the @


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley if I understand you correctly, you'd put the accumulator in a variable outside the expression and mutate it there? Doesn't sound very functional if you ask me - and fucks you up when you apply more combinators later on.

    I've been playing with this.

    val s = List("abc", "x", "qwerty", "asdf")
    val i = (1 to 1000).toList
    val iter = i.iterator
    
    s.map(x => (x, iter.take(x.length).toList))
    // result: List((abc,List(1, 2, 3)), (x,List(4)), (qwerty,List(5, 6, 7, 8, 9, 10)), (asdf,List(11, 12, 13, 14)))
    

  • Banned

    @mikehurley so I was right.


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley so I was right.

    What are you calling the accumulator? There is no accumulator, at least not as I've normally seen that term used. After the map runs s and i are both unchanged. The iterator changes since that's the nature of iterators. This is essentially doing a custom form of what scala calls zip. But zip is fairly dumb and just correlates the ith items from each sequence.

    I guess it depends on what definition you use, but my understanding is state is not disallowed in functional programming, but it is strongly discouraged.


  • Trolleybus Mechanic

    @mikehurley said in I hate Scala:

    @gąska said in I hate Scala:

    @mikehurley so I was right.

    What are you calling the accumulator? There is no accumulator, at least not as I've normally seen that term used. After the map runs s and i are both unchanged. The iterator changes since that's the nature of iterators. This is essentially doing a custom form of what scala calls zip. But zip is fairly dumb and just correlates the ith items from each sequence.

    I guess it depends on what definition you use, but my understanding is state is not disallowed in functional programming, but it is strongly discouraged.

    You could save that final list and do whatever you want to it with no state problems. Same with s and i. You'd want to throw iter away.


  • Impossible Mission - B

    @mikehurley said in I hate Scala:

    I guess it depends on what definition you use, but my understanding is state is not disallowed in functional programming, but it is strongly discouraged.

    It all depends on how pure you're being.


  • BINNED

    @gąska said in I hate Scala:

    That's it. The entire function's body is { self }. Literally just returning itself. And by the magic of Rust type system, it does something extremely useful. Absolutely stunning.

    Is this more surprising than the following?

    template<typename T> const T& to_const(T& val) { return val; }
    



  • Banned

    @mikehurley said in I hate Scala:

    You could save that final list

    Oh right, forgot that Scala evaluates everything eagerly. So yeah, no problem there, other than excessive memory usage.


  • BINNED

    @lb_ said in I hate Scala:

    @topspin http://en.cppreference.com/w/cpp/utility/as_const

    std::add_const_t<T>& as_const(T& t)

    Possible implementations:
    template< class T> struct add_const { typedef const T type; };

    I don't get it, what's the point of not using const T& directly?


  • Banned

    @topspin said in I hate Scala:

    @gąska said in I hate Scala:

    That's it. The entire function's body is { self }. Literally just returning itself. And by the magic of Rust type system, it does something extremely useful. Absolutely stunning.

    Is this more surprising than the following?

    template<typename T> const T& to_const(T& val) { return val; }
    

    What cool stuff can you do with a function like that? Because Rust's by_ref() lets you apply iterator-consuming combinators wihout actually consuming it.


  • BINNED

    @gąska Call const overloads (of methods having both const and mutable versions) on mutable objects, mostly.

    But is there any more magic in the Rust function than is seen here, or is it just that the result (a converted type) that let's you do cool stuff?


  • Banned

    @topspin said in I hate Scala:

    @gąska Call const overloads (of methods having both const and mutable versions) on mutable objects, mostly.

    Sounds like a very bad idea.

    But is there any more magic in the Rust function than is seen here, or is it just that the result (a converted type) that let's you do cool stuff?

    The other piece of magic is impl<I: Iterator> for &mut I, also included in standard library. Basically, a mut reference to iterator is also an iterator, so things that take iterator by value can take mut reference instead.


  • BINNED

    @gąska said in I hate Scala:

    @topspin said in I hate Scala:

    @gąska Call const overloads (of methods having both const and mutable versions) on mutable objects, mostly.

    Sounds like a very bad idea.

    Why? The other way around would be, but that's not what's happening.



  • @topspin said in I hate Scala:

    @lb_ said in I hate Scala:

    @topspin http://en.cppreference.com/w/cpp/utility/as_const

    std::add_const_t<T>& as_const(T& t)

    Possible implementations:
    template< class T> struct add_const { typedef const T type; };

    I don't get it, what's the point of not using const T& directly?

    It doesn't matter, T would have const applied to it as needed. There's no difference I'm aware of, though it might be to prevent non-const stuff from binding to the deleted overload for rvalue references.


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    @mikehurley said in I hate Scala:

    You could save that final list

    Oh right, forgot that Scala evaluates everything eagerly. So yeah, no problem there, other than excessive memory usage.

    I had to make it eager with the .toList() inside the map() otherwise the iterator doesn't march along.


  • Banned

    @topspin said in I hate Scala:

    @gąska said in I hate Scala:

    @topspin said in I hate Scala:

    @gąska Call const overloads (of methods having both const and mutable versions) on mutable objects, mostly.

    Sounds like a very bad idea.

    Why? The other way around would be, but that's not what's happening.

    When you need to convert non-const reference to const reference in order to use const reference overload, it means there is a non-const overload present. If someone made separate overloads for const and non-const references, they presumably did it for a reason. By using const overload on a reference you've received as non-const, you're basically saying that the author is wrong and his reason is invalid. And you might be right to think that, but you need a really solid argument to convince me.


  • Banned

    @mikehurley said in I hate Scala:

    @gąska said in I hate Scala:

    @mikehurley said in I hate Scala:

    You could save that final list

    Oh right, forgot that Scala evaluates everything eagerly. So yeah, no problem there, other than excessive memory usage.

    I had to make it eager with the .toList() inside the map() otherwise the iterator doesn't march along.

    But what about the outer sequence? Is the map itself eager or lazy? It's surprisingly hard to google up, and while I used to know it, I always forget which one it is whenever I need to know.

    If map is eager, you have potentially wasted memory. If map is lazy, you have potentially incorrect or inconsistent results if you don't remember you can't copy it.


  • Trolleybus Mechanic

    @gąska In pure scala I don't know. I think lazy until something like toList is called on it. The only thing you'd have to worry about if it's lazy is if somebody monkeys with the list before the iterator is used. I'm used to using Spark implementations which are lazy/definition-only until you explicitly run a Spark action (count, write to file, etc).


  • Banned

    Of all the things that drive me mad, there's one feature that's quite nice: a Map container implements function interface, so you can pass it as the mapping function to map method on sequences.

    Still, not as cool as Rust's entry(), which lets you find out if an element is in a map, do some complicated operations in the meantime, and then conditionally insert, update or remove the element without a second lookup.


  • Impossible Mission - B

    @gąska said in I hate Scala:

    Because Rust's by_ref() lets you apply iterator-consuming combinators wihout actually consuming it.


  • Banned

    Scalariform, the autoformatting tool we use in our project, can't deal with trailing commas in lists. It just blows up with illegal start of simple expression: Token(RPAREN,),812,)). It has been reported almost a year ago, and still hasn't been fixed.


  • Banned

    What's the easiest way to get NullPointerException in Scala?

    1. Override a field.
    2. Create your object.

    And you're done! See, when you override a field, its value is only set when the derived class constructor runs, and derived class constructor runs after the base class constructor finishes. So the field becomes null for the entire duration of base class construction, and there's nothing you can do to prevent it! When making non-sealed class, EVERY SINGLE PUBLIC AND PROTECTED FIELD IS POTENTIALLY NULL!!! Isn't Scala fun?


  • Trolleybus Mechanic

    @gąska said in I hate Scala:

    What's the easiest way to get NullPointerException in Scala?

    1. Override a field.
    2. Create your object.

    And you're done! See, when you override a field, its value is only set when the derived class constructor runs, and derived class constructor runs after the base class constructor finishes. So the field becomes null for the entire duration of base class construction, and there's nothing you can do to prevent it! When making non-sealed class, EVERY SINGLE PUBLIC AND PROTECTED FIELD IS POTENTIALLY NULL!!! Isn't Scala fun?

    Wouldn't it have the definition of the base class until then?


  • ♿ (Parody)

    @gąska said in I hate Scala:

    Override a field.

    That seems like some serious :doing_it_wrong:. Does it not at least throw a warning?


  • Banned

    @mikehurley no.


  • Banned

    You know what's cool in Scala? That you can just val Seq(x) = getSeq() and it automatically checks if it's one-element sequence and assign the only element to variable, or throw exception/move on to next case if it's not.

    You know what would be cool in Scala? If you could just val Set(x) = getSet() and it would automatically check if it's one-element set and assign the only element to variable, or throw exception/move on to next case if it's not.

    So similar, yet so different. Have Scala devs ever heard of the principle of least astonishment?

    Edit: and don't even get me started on the automatic conversions going on in map, collect and similar methods makes it impossible to tell which parts of the expression are of duplicate-preserving type Seq and which are of duplicate-removing type Set. Which has bitten me in ass once already.



  • I didn't read this topic for a while, let's remind me what it was about

    @gąska said in I hate Scala:

    @sockpuppet7 I'm saying go fuck yourself.

    closes window



  • This post is deleted!

  • Banned

    @sockpuppet7 said in I hate Scala:

    I didn't read this topic for a while, let's remind me what it was about

    @gąska said in I hate Scala:

    @sockpuppet7 I'm saying go fuck yourself.

    closes window

    I don't even remember what it was about. But I'm sure I've had a good reason.


  • Banned

    @sockpuppet7 said in I hate Scala:

    @gąska said in I hate Scala:

    @dfdub we have suffered DECADES of cultural hegemony of USA in the IT world. We were denied using our own language because some sorry ass "developers" from the other side of planet couldn't be arsed to support more than 95 characters even though it would cost them nothing. UTF-8 took over ASCII only in the late 2000s, but there are still fucktards who don't care to implement it. For them, it's just fancy 'a'; for me, it's my national identity. My language has 32 distinct letters, and I want to use them all to full extent, because otherwise I can't write half the worlds correctly. I know Americans don't give a fuck about correct spelling, but is it really that hard to imagine some people do? Do you really think your fat fingers justify erasing my culture? You could have at least said you're sorry or something. But instead you called ME culturally unsensitive. Oh, the irony!

    Fuck technological imperialism.

    BTW, you can enable additional character sets quite easily in keyboard settings. You have to select English as your primary language and others as additional languages. Additional languages have no effect on anything whatsoever except available character sets.

    Sorry, I'm not changing keyboard configs because of your non-ascii character. My name has a non-us-ascii character on it too, I don't ask foreign people to type it correctly.

    I should probably make a new topic for my rants, so people won't reignite old discussions.




  • Notification Spam Recipient

    @Gąska said in I hate Scala:

    What I hate Scala for today: variable is introduced in scope (and shadows other variables with the same name) before initialization. In other words, val x = foo(); val x = bar(x) doesn't work.

    BAD DOG!


Log in to reply