On Wed, 6 Apr 2022 at 16:51, Brian McCall
<brian.patrick.mcc...@gmail.com> wrote:
> Before I get to this example, though, there is more to arguments for the 
> "need" than just counter-examples. I keep using quotes because nothing is 
> really a need for anything.

Yes, it's not about "need" in an absolute sense, but more about
whether the gains justify the costs. In this case, the costs are
non-trivial, because there's very little prior art (at least that I
know of) in other programming languages in this area. So there's a
learning curve, making Python a bit less approachable for the average
programmer, which offsets the benefits to people who gain from this
sort of functionality. And that's on top of the usual costs of any
syntax change/new language feature.

> Alright, now let's look at an example. Again, it's not my best, let's go with 
> it.

Thanks for this, it helps a lot to have something concrete.

> Symbol definitions:
> h - Planck's constant
> c - speed of light
> Ee - irradiance
> R - reflectance
> Q - quantum efficiency
> F - f-number
> λ - wavelength
> a - width of a pixel
> t - exposure time
> ȳ - output of luminosity function integral
>
> From here, if the triple tick marks do not render this example in monospace 
> for you, then I recommend copy/pasting into something that does.
>
> ```
> echo no units
>
> python -c "
> h  = 6.62607015e-34
> c  = 299792458
> Ee = 200
> R  = 0.25
> Q  = 0.63
> F  = 2.4
> λ  = 550e-9
> a  = 3.45e-6
> t  = 30e-3
> ȳ  = 683
> n  = (Ee * R * Q * λ * t * a**2) / (2 * h * c * ȳ * F**2)

Someone's already asked, so I know that the issue was with the value
given to one of the constants, rather than with the formula. And I
know all of this is intended to be read by specialists, not by the
likes of me, but I wonder whether some comments might have helped
here, as well?

t  = 30e-3 # exposure time (seconds)

There's a subtle difference between "scripting" and "programming", and
as a programmer, I'd almost certainly add comments like this. But if I
was writing a script, I wouldn't. However, I'd generally not trust the
output of a script as much as I would that of a program. (Jupyter
notebooks fall somewhere in between, for what it's worth...)

> # n  = (200 * 0.25 * 0.63 * 550e-9 * 30e-3 * (3.45e-6)**2) / (2 * h*c * 683 * 
> 2.4**2)
> print(n)
> "
>
> # Pros - compact, the code representing the equation is easily verifiable, 
> and the magnitudes are also easily verifiable

Given that the error was in the magnitude of one of the values,
"magnitudes are easily verifiable" doesn't really seem that correct...

> # Cons - no units

Agreed, this is just using Python as a glorified calculator. I
understand that this is just an example, but I *am* curious, is the
bulk of what you do simply calculations like this, or do your more
complicated examples tend to be more like actual programs?

>
> echo What literals would look like
> python -c "
> # h  = 6.62607015e-34m2kg / 1s
> # c  = 299792458m / 1s
> # Ee = 200lx
> # R  = 0.25
> # Q  = 0.63
> # F  = 2.4
> # λ  = 550e-9nm
> # a  = 0.00345mm
> # t  = 30ms
> # ȳ  = 683lm / 1W
> # n  = (Ee * R * Q * λ * t * a**2) / (2 * h * c * ȳ * F**2)
> # n  = (200lx * 0.25 * 0.63 * 500nm * 30ms * (3450nm)**2) / (2 * h*c * 
> 683lm/1W * 2.4**2)
> "
> # Pros - Still compact. Dead simple. Planck's constant looks a little weird, 
> but this is usually imported from a library anyway
> # Cons - requires a syntax change; inline computations like the last line are 
> not IMO quite as readable as the next example

What would the output of "print(n)" be here? Presumably you'd be
expecting some sort of calculation on the units, so you didn't just
get something like

3958.0636423739215lxnm3msWs2/m2kglm

Or is that sufficient for you (I note that it's the same as units
provides, below)? Excuse me if I got the scale of the constant wrong,
you changed the units between the no-units example and this one (t,
for example was seconds and is now ms).

> echo 'What bracket syntax might look like'
> python -c "
> # h  = 6.62607015e-34 [m**2*kg/s]
> # c  = 299792458      [m/s]
> # Ee = 200            [lx]
> # R  = 0.25
> # Q  = 0.63
> # F  = 2.4
> # λ  = 550e-9         [nm]
> # a  = 0.00345        [mm]
> # t  = 30             [ms]
> # ȳ  = 683            [lm/W]
> # n  = (Ee * R * Q * λ * t * a**2) / (2 * h * c * ȳ * F**2)
> # n  = (200[lx] * 0.25 * 0.63 * 500[nm] * 30[ms] * (0.00345[mm])**2) / (2 * 
> h*c * 683[lm/W] * 2.4**2)
> "
>
> # Pros - Still compact, dead simple, and IMO the best way to look at this code
> # Cons - requires a syntax change and a new kind of namespace in addition to 
> global, nonlocal, and enclosure

This is basically just a different bikeshed colour for the previous
example, I think. Is that right?

> echo units
> python -c "
> from units import unit
> h  = unit('m**2*kg/s')    (6.62607015e-34)
> c  = unit('m/s')          (299792458)
> Ee = unit('lx')           (200)
> R  =                       0.25
> Q  =                       0.63
> F  =                       2.4
> λ  = unit('nm')           (550)
> a  = unit('mm')           (0.00345)
> t  = unit('ms')           (30)
> ȳ  = unit('lm/W')         (683)
> n  = (Ee * R * Q * λ * t * a**2) / (2 * h * c * ȳ * F**2)
> print(n)
> n  = unit('lx')(200) * 0.25 * 0.63 * unit('nm')(550) * unit('mm')(0.00345)**2 
> * unit('ms')(30) / (2 * 2.4**2 * h*c) / unit('lm/W')(683)
> print(n)
> "

This seems pretty readable to me, but I concede I'm a non-expert in
this field. However, it's very hard to judge this without seeing the
output. So I installed units and ran it, and I get

3958063642373921964032.00 lx * mm * mm * nm * ms / m**2*kg/s * m/s * lm/W

Hmm. I'll take your word for it that this (a) is readable and useful
to you, and (b) would have helped you spot the error you made.

> # Pros - Has units, and no syntax change required

A significant pro, in my view. Not least because it means you can use
it *right now*.

> # Cons - less compact

I guess so, but compactness isn't typically regarded as a significant
selling point for a proposal.

> # Cons - How do you get the final answer? You need to know that units became 
> astropy.units and see below

Please can you explain this to me? I don't know what you mean by "get
the final answer", nor do I know how astropy.units is relevant. Units
seems to be a perfectly acceptable library without astropy, is that
not the case?

> # Cons - Not dead simple. Multiple adjacent ()() is going to be unpopular 
> with the crowd that uses Python as if it were Fortran/Matlab

It seems dead simple to me, and as for the adjacent parentheses,
presumably you can name the units you need, like:

ms = unit('ms')
t = ms(30)

It's not as close to natural language as "30 ms", but again, that's a
fairly minor disadvantage in these types of discussion (and opens up a
lot of debate about subjective issues like what "looks natural").

> echo astropy.units
> python -c "
> import astropy.units as units
> h  = 6.62607015e-34       * units.m**2*units.kg/units.s
> c  = 299792458            * units.m / units.s
> Ee = 200                  * units.lx
> R  = 0.25
> Q  = 0.63
> F  = 2.4
> λ  = 550                  * units.nm
> a  = 0.00345              * units.mm
> t  = 30                   * units.ms
> ȳ  = 683                  * units.lm / units.W
> n  = (Ee * R * Q * λ * t * a**2) / (2 * h * c * ȳ * F**2)
> print(n)
> n  = (200*units.lx * 0.25 * 0.63 * 550*units.nm * 30*units.ms * 
> (0.00345*units.mm)**2) / (2 * h*c * 683*units.lm/units.W * 2.4**2)
> print(n)
> print(n.decompose())
> "
>
> # Pros - Has units, and no syntax change required
> # Cons - less compact, everything is an instance of numpy.ndarray which will 
> break some existing code
> # Cons - .decompose() is required to convert final result
> # Cons - dot-notation is better than ()(), but again will encounter 
> resistance from those who use Python as if it were Fortran/Matlab

As has been mentioned, if you don't like "units." then "from astropy
import units as U" and use "U.ms" of "from astropy.units import ms"
and use ms directly.
The fact that things are ndarrays is presumably because astropy is
intended for use with numpy. I would not expect a library for general
use to have such a constraint.
I don't know why .decompose() is needed, but again that's an
implementation detail of astropy.

> echo astropy.units again, but importing everything into globals
> python -c "
> from astropy.units import *
> h  = 6.62607015e-34       * m**2*kg/s
> c  = 299792458            * m/s
> Ee = 200                  * lx
> R  = 0.25
> Q  = 0.63
> F  = 2.4
> λ  = 550                  * nm
> a  = 0.00345              * mm
> t  = 30                   * ms
> ȳ  = 683                  * lm/W
> n  = (Ee * R * Q * λ * t * a**2) / (2 * h * c * ȳ * F**2)
> print(n)
> n  = (200*lx * 0.25 * 0.63 * 550*nm * 30*ms * (3450*mm)**2) / (2 * h*c * 
> 683*lm/W * 2.4**2)
> print(n)
> print(n.decompose())
> "
>
> # Pros - Compact, has units, and no syntax change required
> # Cons - Everything is an instance of numpy.ndarray which will break some 
> existing code

Already noted above

> # Cons - Can't use "m" as a counter (and other namespace collisions)

Don't use "import *" then, just import the names you need.

> # Cons - .decompose() is required to convert final result

Already noted above.

> # Cons - dot-notation is better than ()(), but again will encounter 
> resistance from those who use Python as if it were Fortran/Matlab

Already noted above.

> echo Quantiphy
[...]
> # Ugh

No further comment :-)

These examples were very useful. Thanks for providing them. I'm not
trying to shoot them down by doing a point-by-point response, but I
wanted to explain some of my thoughts. Overall, my feeling is that the
existing library solutions might not be ideal, but they do broadly
address the requirement, as I interpret it from your explanations.
Yes, the notation may be suboptimal for an expert, but there's always
going to be *some* level of compromise needed, and having to write "35
* mm" rather than "35 mm" doesn't seem impossible. On the other hand,
it seems clear to me that the various libraries all have their problem
points at the moment. Maybe that suggests that there's room for a
unified library that takes the best ideas from all of the existing
ones, and pulls them together into something that subject experts like
yourself *would* be happy with (within the constraints of the existing
language). And if new syntax is a clear win even with such a library,
then designing a language feature that enables better syntax for that
library would still be possible (and there would be a clear use case
for it, making the arguments easier to make).

I should say, though, that I doubt I'll ever use such a new syntax, or
even the existing libraries, for anything other than experimentation.
So treat my comments with that in mind.

Paul
_______________________________________________
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/MACTZYFALYLO5K6UC6X3YOZWSPRM3YXB/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to