On Aug 27, 2019, at 14:41, Chris Angelico <ros...@gmail.com> wrote:
> 
>> On Wed, Aug 28, 2019 at 6:03 AM Andrew Barnert <abarn...@yahoo.com> wrote:
>> 
>>> On Tuesday, August 27, 2019, 11:12:51 AM PDT, Chris Angelico 
>>> <ros...@gmail.com> wrote:
>>> If your conclusion here were "and that's why Python needs a proper
>>> syntax for Decimal literals", then I would be inclined to agree with
>>> you - a Decimal literal would be lossless (as it can entirely encode
>>> whatever was in the source file), and you could then create the
>>> float32 values from those.
>> 
>> I think builtin Decimal literals are a non-starter. The type isn't even 
>> builtin.
>> 
> 
> Not sure that's a total blocker, but in any case, I'm not arguing for
> that - I'm just saying that everything up to that point in your
> argument would be better served by a Decimal literal than by any
> notion of "custom literals".

No, it really couldn’t. A builtin Decimal literal would arguably serve the 
Decimal use case better (but I’m not even sure about that one; see below), but 
it doesn’t serve the float32 case that you’re responding to.

>> But they're not. You didn't even attempt to answer the comparison with 
>> complex that you quoted. The problem that `j` solves is not that there's no 
>> way to create complex values losslessly out of floats, but that there's no 
>> way to create them _readably_, in a way that's consistent with the way you 
>> read and write them in every other context. Which is exactly the problem 
>> that `f` solves. Adding a Decimal literal would not help that at all—letting 
>> me write `f(1.23d)` instead of `f('1.23')` does not let me write `1.23f`.
>> 
> TBH I don't quite understand the problem. Is it only an issue with
> negative zero? If so, maybe you should say so, because in every other
> way, building a complex out of a float added to an imaginary is
> perfectly lossless.

Negative zero is an irrelevant side issue that Serhiy brought up. It means j is 
not quite perfect—and yet j is still perfectly usable despite that. Ignore 
negative zero.

The problem that j solves is dead simple: 1 + 2j is more readable than 
complex(1, 2). And it matches what you write and read in other contexts besides 
Python. That’s the only problem j solves. But it’s a problem worth solving, at 
least for code that uses a lot of complex numbers. Without it, even if you 
wanted to pollute the namespace with a single-letter global so you could write 
c(1, 2) or 1 + j(2), it _still_ wouldn’t be nearly as readable or as familiar. 
That’s why we have j. There is literally no other benefit, and yet it’s enough.

And the problem that f solves would be exactly the same: 1.23f is more readable 
than calling float32, and it matches what you read and write in other contexts 
besides Python (like, say, C or shader code). Even if you wanted to pollute the 
namespace with a single-letter global f, it still wouldn’t be as readable or as 
familiar. That’s why we should have f. There is literally no other benefit, but 
I think it’s enough benefit, for enough programs, that we should be allowed to 
do it. Just like j.

Unlike j, however, I don’t think it’s useful in enough programs that it should 
be builtin. And I think the same is probably true for Decimal. And for most of 
the other examples that have come up in this thread. Which is why I think we’d 
be better served with something akin to C++ allowing you to explicitly register 
affixes for your specific program, than something like C with its too-big-to 
remember-but-still-not-enough-for-many-uses zoo of builtin affixes.

>> Also, as the OP has pointed out repeatedly and nobody has yet answered, if I 
>> want to write `f(1.23d)` or `f('1.23')`, I have to pollute the global 
>> namespace with a function named `f` (a very commonly-used name); if I want 
>> to write `1.23f`, I don't, since the converter gets stored in some 
>> out-of-the-way place like `__user_literals_registry__['f']` rather than `f`. 
>> That seems like a serious benefit to me.
>> 
> Maybe. But far worse is that you have a very confusing situation that
> this registered value could be different in different programs. 

Sure, and the global f could also be different in different programs—or even in 
different modules in the same program. So what?

1.23f would always have the same meaning everywhere, it’s just that the meaning 
is something like __user_literals__['f']('1.23') instead of 
globals()['f']('1.23').

Yes, of course that is something new to be learned, if you’re looking at a 
program that does a lot of 3D math, or a lot of decimal math, or a lot of 
Windows path stuff, or whatever, people are likely to have used this feature so 
you’ll need to know how to look up the f or d or whatever. But that really 
isn’t a huge hardship, and I think the benefits outweigh the cost. 

> In
> contrast, f(1.23d) would have the same meaning everywhere: call a
> function 'f' with one parameter, the Decimal value 1.23. Allowing
> language syntax to vary between programs is a mess that needs a LOT
> more justification than anything I've seen so far.

This doesn’t really allow syntax to vary between programs. It just allows 
literals to be followed (or maybe preceded) by tags. The rest of the syntax is 
unchanged.

>>> But you haven't made the case for generic string prefixes or any sort
>>> of "arbitrary literal" that would let you import something that
>>> registers something to make your float32 literals.
>> 
>> Sure I did; you just cut off the rest of the email that had other cases.
> 
> Which said basically the same as the parts I quoted.

Not even remotely—again, unless you think that Windows paths could somehow be 
served by builtin decimal literals?

>> And ignored most of what you quoted about the float32 case.
> 
> What did I ignore?

That 1.23f is more readable, familiar, etc. in exactly the same way that 2.3j 
is.

>> And ignored the previous emails by both me and the OP that had other cases. 
>> Or can you explain to me how a builtin Decimal literal could solve the 
>> problem of Windows paths?
> 
> All the examples about Windows paths fall into one of two problematic boxes:
> 
> 1) Proposals that allow an arbitrary prefix to redefine the entire
> parser - basically impossible for anything sane
> 
> 2) Proposals that do not allow the prefix to redefine the parser, and
> are utterly useless, because the rest of the string still has to be
> valid.

3) Proposals that do not allow the prefix to redefine the parser for the entire 
program, but do allow it to manually parse anything the tokenizer can recognize 
as a single (literal) token.

As I said, I haven’t tried to implement this example as I have with the other 
examples, so I can’t promise that it’s doable (with the current tokenizer, or 
with a reasonable change to it). But if it is doable, it’s neither insane nor 
useless. (And evenif it’s not doable, that’s just two examples that affixes 
can’t solve—Windows paths and general “super-raw strings”. They still solve all 
of the other examples.)

>> Here's a few more: Numeric types that can't be losslessly converted to and 
>> from Decimal, like Fraction.
> 
> If you want to push for Fraction literals as well, then sure. But
> that's still very very different from *arbitrary literal types*.

If we really only ever needed Decimal and Fraction, then yes, I think allowing 
user-defined literal tags would be better than adding two hard-coded tags that 
most people will rarely use.

>> I think your reluctance and the OP's excitement here both come from the same 
>> source: Any feature that gives you a more convenient way to write and read 
>> something is good, because it lets you write things in a way that's 
>> consistent with your actual domain, and also bad, because it lets you write 
>> things in a way that's not readable to people who aren't steeped in your 
>> domain. Those are _always_ both true, so just arguing from first principles 
>> is pointless. The question is whether, for this specific feature, there are 
>> good uses where the benefit outweighs the cost. And I think there are.
> 
> That line of argument is valid for anything that is specifically
> defined by the language.

Yes, and? “Literal token” is specifically defined by the language. “Literal 
token with attached tag” will also be specifically defined by the language. The 
only thing open to customization is what that token gets compiled to.

(Or course this is just one suggestion I came up with, not the only way to do 
things, or what the OP suggested. But it does show that there is at least one 
possibility besides “insane” and “useless”.)

Your argument comes down to the fact that anything that could possibly be 
construed as affecting syntax, no matter how constrained it is, and no matter 
how far you have to stretch to see it as affecting syntax in the first place, 
and even if nobody would ever do that with it, is Inherently so evil that it 
can’t possibly be allowed. I think that’s a silly argument. Especially in a 
language that already has a nicely documented feature like, say, import hooks.

>> In fact, if you're already convinced that we need Decimal literals, unless 
>> you can come up with a more feasible way to add builtin Decimal literals to 
>> Python, Decimal on its own seems like a sufficient use case for the feature.
> 
> There are valid use cases for Decimal literals and Fraction literals,
> but not, IMO, for custom literals. Look at some of the worst abuses of
> #define in C to get an idea of what syntax customization can do to
> readability.

Look at the plethora of suffixes C has for number and character literals. Look 
at how many things people still can’t do with them that they want to.

Look at the way user literals work in C++. While technically you can argue that 
they are “syntax customization”, in practice the customization is highly 
constrained. Is it _impossible_ to use that feature to write code that can’t be 
parsed by a human reader? I don’t know if I could prove that it’s impossible. 
However, I do know that it’s not easy. And that none of the examples, or 
real-life uses, that I’ve seen have done so.

Do you think Python users are incapable of the kind of restraint and taste 
shown by C++ users, and therefore we can’t trust Python users with a tool that 
might possibly (but we aren’t sure) if abused badly enough make code harder to 
visually parse?

_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/4PX6Q7K7LO2BLLBVRZLNQAI2I4UBUWAT/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to