News for hackers. Stuff that matters.
Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @04:50AM (#14681576)
I've written commercial code to handle decidedly non-english languages in python2 just fine. Have you? Do you understand unicode and it's encodings well enough to have an informed opinion that python3's braindamaged unicode implementation is superior to working mostly at the byte string level in python2? Hint: this is much closer to what string handling in sensibly designed languages like Rust and Go or Erlang looks like.
Re:Memory use in CPython and MicroPython by rtpg on Sunday July 02, 2017 @07:48AM (#14682088)
I handled a transition of a multilingual/multiencoding Python 2 project to Python 3.

Firstly, you can _still_ work entirely in bytes in Python 3 if you want to. But you can't call print on them... For good reason! You don't know the encoding to use to display them!

When we transitioned, there were a lot of subtle issues in our code due to our almost cargo cult usage of encoded/decode that ended with a lot of redundant transformations. Loads of that disappeared afterwards.

You can still operate in "Python 2 mode" in Python 3. The only exception I can think of is the difficulty in getting a bytestream version of standard output.

Also... Python 2 is decidably not like Go or Rust. The simplest example is how json.dumps would return bytes or a Unicode string depending on the keys on your object. No respect for typing

Re:Memory use in CPython and MicroPython by dom0 on Sunday July 02, 2017 @09:54AM (#14682495)
> The only exception I can think of is the difficulty in getting a bytestream version of standard output.

sys.{stderr, stdout, stdin}.buffer

Re:Memory use in CPython and MicroPython by masklinn on Sunday July 02, 2017 @06:12AM (#14681818)
> Hint: this is much closer to what string handling in sensibly designed languages like Rust and Go or Erlang looks like.

* Rust has a very strict split between bytes and text

* Go has fucked up bytestrings which depending on validity may break at any point depending on the API you're applying

* Erlang's strings are widely considered awful, and are literally just linked lists of integers making them slow, memory-heavy and prone to pretty-printer whims (as the pretty printer decides on the fly whether a given list looks like a string — and should be printed thus — or does not — and should be printed as a regular list of integers)

Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @01:03PM (#14683283)
Erlang's strings might be widely considered awful, but probably not by people who actually have a clue – the numbers thing is ugly, but overall it's a very nice design and has very nice features that are pretty much unique to Erlang.

Erlang has 3 types of strings:

1. the list of integers thing, which you should mostly avoid

2. binary strings (like python2 str or go)

3. iolists: a list or element of either of 1, 2 or 3. This is the nice part – it basically means erlang has ropes. And all the "egress" functions (sending udp or tcp packets or writing to stdout or files or sockets etc.) take iolists. So you can avoid a lot of pointless copying and write text or binary data very efficiently; I know of no other (non-BEAM) language that has similarly good support for this, do you?

See http://www.evanmiller.org/elixir-ram-and-the-template-of-doo... for more details.

Re:Memory use in CPython and MicroPython by masklinn on Sunday July 02, 2017 @03:21PM (#14683919)
> Erlang's strings might be widely considered awful, but probably not by people who actually have a clue – the numbers thing is ugly, but overall it's a very nice design

It is nice in a theoretical sense, in the same way Haskell's [Char] is nice, in a practical sense it's awful.

> 2. binary strings (like python2 str or go)

AKA not actually strings, I don't remember Erlang having much if any string-manipulation API for working on bytes.

> 3. iolists: a list or element of either of 1, 2 or 3. This is the nice part – it basically means erlang has ropes. And all the "egress" functions (sending udp or tcp packets or writing to stdout or files or sockets etc.) take iolists.

This is only for output, so they're not actually ropes.

> So you can avoid a lot of pointless copying and write text or binary data very efficiently; I know of no other (non-BEAM) language that has similarly good support for this, do you?

Most mutable languages will use buffered output streams and possibly some sort of string sequence (even C has iovecs), so while iolists are a good fit for Erlang they make sense in few other languages.

Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @04:22PM (#14684166)
> It is nice in a theoretical sense, in the same way Haskell's [Char] is nice, in a practical sense it's awful.

Haskell's list of Char is awful in both a theoretical and practical sense whereas in erlang's case you can think of it as just a degenerate iolist.

> I don't remember Erlang having much if any string-manipulation API for working on bytes

Elixir is better but erlang certainly has string manipulation functionality for binaries: pattern matching, regular expressions, search, splitting and joining etc.

> This is only for output, so they're not actually ropes.

Not true, lots of non-output functions also accept iolists, e.g. the re module.

Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @01:15PM (#14683341)
BTW, I agree that you want to differentiate between bytes and text, but the underlying representation should be utf-8 bytes, not some constant time indexable utf-32, which is a semantics and performance disaster. It's much better to mess up in not having a clear distinction between bytes and text (annoying, but mostly easy to work around) then to mess up by having constant-time indexable utf-32 as python3 does (not at all easy to work around and even the bits that are easy to work around, like pretending stdin or stdout and sys.argv are unicode on unix are still super-annoying).
Re:Memory use in CPython and MicroPython by masklinn on Sunday July 02, 2017 @03:24PM (#14683927)
> BTW, I agree that you want to differentiate between bytes and text, but the underlying representation should be utf-8 bytes

Sure, but for most languages older than a few years this ship has sadly long sailed and few would be willing to switch to O(n) indexing.

> It's much better to mess up in not having a clear distinction between bytes and text (annoying, but mostly easy to work around)

Except when it's not and the packages you're trying to use simply do not work and fuck up mightily with non-ascii data.

> then to mess up by having constant-time indexable utf-32 as python3 does

It's funny that just above you praise Erlang which does exactly that. Meanwhile Python 3.3 introduced a flexible string representation so depending on the content of the string the internal string encoding may be ISO-8859-1, UCS2 or UCS4 (and yes sadly only these as the designers refused to break the constant-time indexing guarantee).

Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @04:24PM (#14684172)
Where's erlang's constant time indexable utf-32 string?
Re:Memory use in CPython and MicroPython by masklinn on Sunday July 02, 2017 @06:19PM (#14684640)
Erlang's strings are even worse than that since they're non-constant time indexable UTF-32.
Re:Memory use in CPython and MicroPython by dom0 on Sunday July 02, 2017 @09:56AM (#14682502)
> Erlang

What the fuck. And I thought constant-time indexable strings were a bad idea!

Re:Memory use in CPython and MicroPython by masklinn on Sunday July 02, 2017 @11:03AM (#14682784)
FWIW it's way too common in functional languages, Haskell's standard String is a typedef for [Char] (a linked list of Char) hence the proliferation of various other string types.
Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @12:51PM (#14683235)
They are. You want to use iolists in Erlang. Constant time concatenation (which is useful) rather than constant time indexing into codepoints (which is not; and erlang does not have BTW).
Re:Memory use in CPython and MicroPython by svennek on Sunday July 02, 2017 @05:23AM (#14681658)
Yes, I have (for more than a decade in four different languages, not all of those who are latin1)... One project was even both LTR and RTL :)

Byte handling is definately not fun in variable encodings, and even fixed-length multi-byte encodings require a lot of support functionality when working with bytes..

Such a simple thing as "len" is suddenly hard (for the human definition of length and not the byte-length), the latter is also easily attainable by converting the string to bytes and get the length of that in the given encoding.

Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @07:42PM (#14684898)
len isn't a great example because it doesn't do anything remotely useful on python3 strs in the general case. In particular it doesn't tell you how many characters the str has, which is what you probably wanted to know -- possibly as an approximation for figuring out how many columns in fixed-width it would take, in which case of course you are even more likely to be disappointed.

In python2 len(str) will tell you exactly how many bytes some text takes, which is useful.

Re:Memory use in CPython and MicroPython by ubernostrum on Sunday July 02, 2017 @07:18AM (#14682001)
Do you understand unicode and it's encodings well enough to have an informed opinion that python3's braindamaged unicode implementation is superior to working mostly at the byte string level in python2?

I do, and I do believe Python 3's approach is superior for strings.

An array of 8-bit integers is not a string. It's an array of 8-bit integers. I want my string type to be a sequence of Unicode codepoints, and I want iterating it to yield codepoints, I want indexing into it to yield the codepoint at the index, and I want the length of it to be the number of codepoints it contains. When I'm ready to send it over a wire or flush it to disk, then I'll think about the best way to represent it as an array of 8-bit integers, but bringing the baggage of encodings (especially the baggage of UTF-8) into any part of my code except the boundary layer is asking for trouble.

Re:Memory use in CPython and MicroPython by patrec on Sunday July 02, 2017 @07:43PM (#14684907)
What's your use case for iterating or indexing into code points?
Re:Memory use in CPython and MicroPython by ubernostrum on Monday July 03, 2017 @04:20AM (#14686733)
My use case is that I don't want iterating/indexing to yield the underlying byte representation, since that may end up slicing up a codepoint large enough to require multiple bytes.

I want the fundamental constituent unit of my strings to be the thing that the string is conceptually made of. When I'm ready to turn it into a sequence of bytes, I'll do that myself.

Re:Memory use in CPython and MicroPython by patrec on Monday July 03, 2017 @06:20PM (#14691888)
But the text is not conceptually made of unicode code points. It's conceptually made of characters. Codepoints are basically ever only used for either

a) low-level mucking around like normalization -- a fringe use

b) a (in the general case) bad approximation to characters -- the normal use, which will produce bad results for various "atypical" cases

Now, personally, I'd often rather muck around with bytes because frequently they are a more useful abstraction than codepoints and lots of in practice important text operations can be performed quite fine (and efficiently) on them, even if the text is full of non-ascii characters.