#internals-and-peps
1 messages ยท Page 99 of 1
I mean, builtin modules are generally wrong, but what about some internal modules or vendoring your own version of some library
I suppose -O0 is a thing but ehhhh
Sounds like exhaustive testing
Static analysis tells you problems that may be able to occur, before they've occurred.
what would do this do other than check for non-parent imports? There isn't a whole lot you can actually warn about, due to how flexible the python runtime is
Yeah. I think that's the elephant in the room isn't it
hell, even 1 is 3, which is a warning, isn't guaranteed to be wrong
This; it makes them more effective in terms of overall safety and purity. Delegating warnings at runtime is about as good as exceptions from how I see it
The reason why C compiler warnings may "feel" more well covered is because the language syntax and specifications of C literally enable it to. That is something fundamentally different from python
What about redefinitions ? also what about code that never will get executed ? if 0 ??
There will be a lot of usages
So, variable declarations for example, python can't flag that because python literally doesn't have such a notion
redefinitions are often deliberate, if 0 is often used to quickly disable an if for testing
then when you want to push your package and you forget to remove that line, DISASTER happens
Yeah. "Dynamic analysis" just sounds like testing.
!e
1 is 3
@flat gazelle :white_check_mark: Your eval job has completed with return code 0.
<string>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
this is a useful one
since as far as the python language spec is concerned, this is always False
also, consider if 0 inside an exec
I mean, there can always be logical errors that no software can save me from. You just need to write tests in that case, and also be diligent about it
but python won't emit a warning if you write if 1 == 3
It's a totally valid expression, albeit useless
Why should it?
yes, because you may want to use that to exemplify some behaviour or inside exec
because that statement is never true
So what? It's a valid statement.
When something is invalid, errors are used, but when something is stupid, warnings are used
At best there's probably some hypothetical mechanism from inlining literals like that
I suppose okay.. Maybe I see what you're asking for. You want a "hey, this might be something dumb" kind of thing
I'd say that's not the job of a compiler or even an interpreter
I'm not asking for it, I'm just sharing my idea
And I'd say such a tool would catch the easy issues and give you a false sense of security
Because as I said earlier, you can't catch all logical errors
ye, it could be a warning perhaps, though I wouldn't like it all that much. Keep in mind that exec and eval are things that are useful for quite a few things, and could generate such expressions
That's why i say it's a good idea, no one else did that
the thing about 1 is 4 is that it is wrong even in exec
This worries me.
nope it won't
So I don't think this is a good idea. I just don't see the benefit.
The interpreter can't tell when code is dead in most cases. Consider ```py
x = True
def foo():
if x:
print("something")
The interpreter has no idea if x is ever True.
I'm taking a hit on performance for a tool that will basically not give me much more benefit
in the end, no amount of static analysis you can fit into python will replace testing
.
And we're just criticizing it.
in the end, I don't think the python interpreter should try to do a better than static analysis tools
Aye. Also, this tool does exist. It's called code review. And even that fails ๐
what it already does is mostly for beginners to quickly spot their errors
Hii,Any one who does coding on platform like hackerearth?
in a way that i had the feeling like you are attacking a all-ready wrote implementation
I hope you didn't feel this was an attack. Just a discussion being fleshed out
Not at all. We're telling you the fundamental limitations behind the idea, that make an implementation unreasonable.
what I do want to see are better syntax error than unkown syntax with the new parser
See ? I never said into python interpreter, Maybe some thing build for newbies
Neither did godly. Hmm.
Implementation aka.. The actual tool or whatever that would be built
Not related to this channel but converting help channel names from chemical names to food names was a good idea
I'm not sure of other ways aside from hooking into the interpreter to perform some sort of dynamic analysis e.g. coverage.py, so I assumed the discussion centered around that. Apologies if I misunderstood what you meant
Hooking into python interpreter to catch awful mistakes is good for teachers, Some stupid stmt can only get caught at runtime
Nah pure, I think that's a very logical "direction" to take, because you'd definitely have to talk about how to implement such a thing to turn it from just an idea into something practical. And then see the shortcomings if any.
I can tell you about coverage.py ๐
Coverage.. Is that the same as pytest-cov?
You either need to be executing the code, or tracing through it. And most of what we've talked about isn't easy to do by tracing through the code.
pytest-cov is a pytest plugin that uses coverage.py to do the meat of the work
Ah I see. Very recently got introduced to that
pytest-cov is a plugin which allows you to take benefits of coverage.py as it was other unittests
I assume it's using some kind of trace to figure out which lines ran
I never really understood the sorcery behind it, just that the general idea that it did tracing by latching on to CPython or something similar
yeah
yes, sys.settrace, same as debuggers and profilers
What surprised me was that it understood that 3 lines separated by brackets was 1 statement. How does that work?
can you show the code?
Hm, not atm since I'm on phone
because it counts statements not lines,
It was basically a function call
Just ```py
if (
1
+ 2
== 3)
In my case it was even simpler, just args spread across diff lines
Ah. This sounds like the relevant bit. So.. What's a statement
your file might be 120239238239 lines but lots of it is docstrings, lines broken into some other lines to make it readable, documentation, etc
if there are questions not answered on that page, I can update it
Anyway, Had a nice time with all of you (I have to go and do magic a bit), bye!
Luckily, compiled Python files (.pyc files) have a table of line numbers in them. Coverage.py reads this table to get the set of executable lines, with a little more source analysis to leave out things like docstrings.
Thanks Ned! That pretty much answered the question I had in my head
Even though I didn't know how to phrase it. I was misassuming it reads the source py file
Thanks as well, I suppose I could apply one or two things there if I ever found the motivation to try and implement a toy language again
Yeah the tracing thing was something I had found out in a pycon talk video (I think?), and it's a bit scary how powerful it is
The talk was about ways to hack together python while debugging to get the answers you needed. Such as when trying to determine what all places were calling a function for example
Let me see if I can find it.
this is a talk i did 10(!) years ago that covers some of this stuff: https://nedbatchelder.com/text/aware.html I should look to see how it holds up
Nice, looking forward to checking it out
Oh gosh, it was literally you Ned. ๐
Speaker: Ned Batchelder
When chasing mysterious bugs, it's helpful to use all the tools at your disposal. We'll explore ways to use Python's dynamic tools to help track down the cause of head-scratching problems in large systems. Tools include the inspect module, monkey-patching, trace functions, and the Python mechanisms at work behind them ...
Unfortunately that video recoding did have a lot of problems, but it was super insightful
oh! that one too.
But.. Uh.. Yeah, that was the video I had seen recently. I suppose this wouldn't bring any new insights to you ๐
that's the time i went 7 minutes over my 25-minute time limit ๐ฆ
I'm sure there's people who wish you had kept going
!e

import json
def use_json(foo, *, json=json):
return json.dumps({"bar": foo})
del json
print(use_json(42))
print(json)
@grave jolt :x: Your eval job has completed with return code 1.
001 | {"bar": 42}
002 | Traceback (most recent call last):
003 | File "<string>", line 9, in <module>
004 | NameError: name 'json' is not defined
I have an idea
@grave jolt that's evil
I'm assuming that it is because globals are resolved when the code object is created?
It uses json from the default arg, which is created at definition
So the default arg json gets tied to the function object
def strStripAll(s,ss):
return ''.join([c for c in s if c not in ss])
what's the point in this over say just using .replace()

so?
def strStripAll(s,ss):
return ''.join([c for c in s if c not in ss])
s = 'q werty 1234567890'
ss4 = strStripAll(s,'97 w')
ss5 = s.replace('97 ','')
ss6 = s.replace('9','').replace('7','').replace(' ','').replace('w','')
how to avoid PermissionError when using tempfile? I want to know how to do it with chmod.Please don't tell run as administrator because that is not a reliable solution. I m on windows . So I cannot use chmod. It would be some win32 api function
how tf does python calculate this: print(2**256) since that's 257 bit computing??? and quickly at that?
okay i tried print(2**(2**256)) which didnt produce an answer since i had to shutdown IDLE
3+Gb of ram usage lmao
python has arbitrary sized ints
Of which it uses 30 bits from each.
each int32s is basically a digit
does it use 32 bit integers for compatibility instead of 64?
In all likely hood yes, though a 32 bit system should still be able to support 64bit numbers however they're stored as two parts which adds a significant slow down
they are yeah
Not really a considerable amount though (compared to the rest of Python's overhead to worry about)
64-bit ints might be faster on 64-bit CPUs, don't quote me on that
I might add an extension to my Python implementation to support native integers
I think java devs measured this and it ends up so incredibly minor that there is very little reason not to use 64bit all the time
32 bit CPUs handle 32 bit ints slightly, but not much, faster than 64 bit ints. 64 bit CPUs handle both about equally fast.
As much as i like the fact python gives you the ability to have an arbitrary sized integer my god are they a pain for the interpreter implementation itself
Considering 99% of all python programs ran will never need anything bigger than a 64 bit int
but if you are going to implement arbitrary ints, then it just adds complexity to also have native-sized ints.
python 2 had both, and now python 3 only has arbitrary-size.
True
Having both means you need to consider both possible types everytime you do something
right, and convert back and forth
imagine also typehinting that
Tbh for that i would do it as a one way system
Haskell has both fixed-size and arbitrarily large integers. And it's so annoying to go back and forth, because different things return different integer types.
that's easy, just add a typing.Integer
well, yes, not that bad
like AnyStr = Union[str, bytes]AnyStr = TypeVar("AnyStr", str, bytes)
yeah. I realize you probably knew that, but it's a common bug I've had to correct my team on repeatedly...
using AnyStr where they meant Union[str, bytes] I mean.
seems like a bit of an unnecessary indirection tbh
like, you could just write
AnyStr = TypeVar("AnyStr", str, bytes)
#or:
S = TypeVar("S", str, bytes)
``` instead of ```py
from typing import AnyStr
what is AnyStr?
but with my architecture semantic concept folding will take care of converting between arbitrary and fixed sized ints
it's a type that can either be bytes or str, but needs to consistently be the same thing for every occurrence in the signature
so ```py
def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b
You can do `concat("a", "b")` or `concat(b"x", b"y")` but not `concat("x", b"y")`
Python used to do that, and it was scrapped because it was slower and more complex.
being slower and more complex may have been down to CPython's architecture more than anything else.
At the level of arithmetic, there's nothing about CPython's architecture involved, beyond CPython's representation of an arbitrary sized integer.
depends on when conversions happen
bc you'll need to check on every op if you need to convert
the conversions can't happen any sooner than the + operator is evaluated, because you can't know the sizes of the integers before that.
they should go full BCD style !
there's decimal.Decimal for that.
well if I add it as an extension I am effectively adding static typing to the language so I can do it before + is evaluated
yes but it should be better integrated ...
are you going to do optimizations based on type hints?
I have yet to research that aspect of Python
no amount of static typing can tell you whether adding two specific int32 values together will give a result that fits in an int32.
^
also yes
if you add two int32 then the result will always be int32 with possible overflow exception
then you've invented an entirely different language that behaves very differently than Python.
but then you'll need to check for overflow in order to convert to arbitrary sized ints
I said it would be an "extension"
which makes it slower
adding a check for overlow will be nowhere near as slow as the aribtrary sized integer stuff
I'm not certain that's true. Arbitrary sized integers that happen to fit in 2**30 should be only very slightly slower than regular 32 bit arithmetic.
well, arbitrary-sized ints already do that
otherwise, how do you know when to add a new chunk?
yeah. Exactly.
except aribtrary sized integers neccessiate an extra level of indirection: a 32-bit int can be held in a register
that might be not that slow, given that IIRC rust does bound checking on integer operations, unless you explicitly say that they're overflowing
wut
They're stores in a int array
No Python object can be stored in a register
they are dynamic in nature so must have an extra level of indirection: you cannot get around this
you're right that there's an indirection, but indirected loads are as cheap as regular loads
they're both one cycle on a CISC architecture - even on most RISC architectures, I believe.
doesn't cpython use a vla to store the digits
it would be challenging to implement Python semantics with some objects held in registers.
registers were just an example: you can also store a 32-bit integer directly in bytecode
yeah, it's a variable length array of 32-bit integers, of which 30 bits are used to store a base-30 digit.
wait so you're implementing them as "primitives"?
i don't know what it means to store data "in bytecode"
that's going to break if someone monkey patches the int class
well, that's not supported by Python anyway, right?
luckily python doesn't let you monkeypatch the int class
you assume I would be using the 'int' class
there's no int class???
you will have to have an int class
um
!e
In CPython, constants are already stored in the function and not created from scratch, so not sure what you mean
import dis
def f(x):
return x in {1, 2, 3}
dis.dis(f)
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | 4 0 LOAD_FAST 0 (x)
002 | 2 LOAD_CONST 1 (frozenset({1, 2, 3}))
003 | 4 CONTAINS_OP 0
004 | 6 RETURN_VALUE
it's certainly possible to switch back and forth between variable length integers and fixed size integers. CPython used to do it.
you assume I would be using the 'int' class FOR FIXED SIZE INTEGERS
It's not a question of whether this is possible, only one of whether it would be faster or slower.
most likely slower, which is why CPython stopped doing it.
ok
perhaps it would be best to just focus on existing Python before inventing non-Python extensions.
So if I understand you right, you have 2 classes, one is normal int, the other is int32?
@sacred yew there is no class yet.
*planned
I might need this extension anyway to make interfacing with the ECS efficient
ecs?
Entity-Component-System
CPython used to do it that way, one was called int and the other was called long. It was possible to implicitly coerce either type to the other (as long as the value fits, in the case of coercing long to int)
but I am focusing on Python first; I will worry about adding any extensions to make it usuble as part of a 3D game engine later
you could choose to not coerce - once you've got the types, you could define different behavior for each.
I don't think any of this is a good idea, but there's absolutely no doubt that it's possible.
but I never add things for the sake of it: there is always some rationale.
>>> numpy.uint32(2**32 - 1) + numpy.uint32(1)
<stdin>:1: RuntimeWarning: overflow encountered in uint_scalars
0
numpy has an unsigned 32 bit integer type with defined defined overflow behavior, for instance.
Yup, and it's still a full Python object, so occupies 28 bytes
isn't it because of compatibility with C types?
C types?
we could go full symbolic with a super big addition 2darray ... :O)
I play long time ago with a 10x10 addition array and number as string .. in lisp ...
I'm not really sure what you mean.
I think @unkempt rock means adding "123" and "456" by looking up "3" + "6" in a 2d-array, etc.
Yeah numpy can already do this no?
In its sleep
well int is 0,1,2 3 .... we just need an addition table 10x10 ans rule to form the summation along int ...
Any sort matrixes operations etc... Might aswell be done with numpy
You're not gonna get anything making it an inbuilt other than compatibility issues 
@weary garden I'm also curious how you plan on supporting haskell
maybe we should just stick to Python ๐
wait until python can be mixed with haskell
@sacred yew the answer to that question is simple: a universal turing machine can compute anything computable; or to put it another way, I do not believe the problem to be intractable.
@weary garden How many langs do you know? And which ones?
@rich cradle why do you ask?
I just want to know what you have going in to this project.
the presumption behind that question then is that you think I lack sufficient knowledge/skill to do what I claim which is kind of insulting to be honest. Should I publish my entire CV in this channel to satisfy your curiosity as to my credibility? Do you want to do the same?
No, that's not what I'm saying. I just want to know what you want to do this with, because I think it may be useful to some people if you made this in multiple langs (the code behind it). I personally, would be interested in seeing that. In how you did it.
That is, if it's open source.
its on github
also, I am implementing languages that I don't currently "know" such as Python. all that is required is the ability to learn new languages and I have that ability.
Leigh is going with there neos system, im going with my web assembly
Round 1, fight!
wasm? LOL. has it got a jmp statement yet? ๐
no, of course the rust compiler for wasm is implemented in pure movs
Web assembly tbh is actually pretty pleasant to write raw
Have you seen that talk at Defcon about Chris Domas' mov-obfuscator? ๐
(although... that's not impossible, maybe, given https://github.com/xoreaxeaxeax/movfuscator)
yes
maybe not that, but heard about it
I think this is handwaving over a lot of hard problems, but we'll see when there's code to run.
a room full of monkeys hammering on typewriters will eventually write a shakespearean sonnet
handwaving? more like a standard repsonse to someone saying something cannot be done when there is no techinical reason why it cannot be done.
it just doesn't provide any information about how you might acheive it, or the enormity of the job.
nobody has written a Haskell compiler in brainfuck/pure turing machine yet, but it's technically possible
adding a Haskell front end to LLVM is not impossible so my approach isn't impossible either.
if you proceed down this line doesn't this mean that you'll eventually write malware, even if unintended
the neos schema in combination with semantic concept libraries is turing complete.
Ngl i think we should just stick with a single language rn
why do one language well when we can do many poorly
Tru
I think you are smart enough to understand the canyon of a gap in this "explanation" ๐
Not really; I have a plan which I am currently executing and I see no technical hurdles too onerous to overcome; the biggest hurdle is simply one of available time.
i'm tempted to ask about mixing languages with very different semantics, like C/Python or Python/Haskell, but my experience in the past says that details aren't forthcoming. We're looking forward to the code.
look at it this way, nedbat, Haskell has pure and impure (imperative) parts which cooperate in parallel. you are simply mistaken in your belief that what I am doing is impossible/intractable.
i didn't say it was impossible. I said i was curious about how you would deal with those difficulties.
the code will speak for itself as and when I come to write it; it is sufficient to know at this point that what I am doing is not impossible/intractable.
ok, no details yet. Like i said, we are looking forward to the code.
added a recurse directive to the neos schema which simplifies schema definitions somewhat; this is slices now:
@weary garden what do the two "expect" terms in a row (lines 722,723 and lines 728,729) mean?
they are the expected tokens to be found when parsing the parent element
so it's a sequence? Both should occur?
i see. i'm trying to see how it works
at first glance you might think it looks a lot more complicated than the PEG grammar but the PEG grammar isn't doing two things: handling whitespace and has no way to embed semantic concepts
for example here is the grammar for a universal number (not Python):
the symbols with dots in them, e.g. exponent.digit are semantic concepts; as are the symbols that can be found by prefixing them with parent.
universal number semantic concepts referenced from the grammar:
i'm curious about the "default: next" bits: it appears a lot
it means any other non-matching token will be parsed as the next unrelated element
without that any other token would cause a syntax error during parsing
this appears to not allow a number to start with .
I originally designed that grammar for Ada unversal numbers so either that is invalid for Ada or I forget it
that # there doesn't seem to apply to Python, either, if that's a literal #
if you scrollback you will see that I stated that this wasn't for Python
ah.
I was just showing you how the grammar looks for something non-trivial
I think @brave badger is writing a novel ๐
2**256 is very quick since it's just a simple bit shift, 1 << 256
Well I wouldn't necessarily say in parallel; the primary abstraction for side effects that Haskell uses e.g. Monads are pure by definition, effects are only observable during runtime when IO is collapsed and observed. Likewise, there's alternative ways to model side effects purely, most of which intrinsically rely on compiler extensions and the type system. I agree that it's not impossible to create an implementation that mixes different effect semantics, but then again I don't want to undermine the past 30 years of research put into the Haskell ecosystem.
I don't think python does it through a bit shift if you do powers
@brave badger However I will be creating a Haskell implementation later this year so prepare for the coming storm! ๐
timing it seems to agree
In [16]: timeit 2**4096
4.15 ยตs ยฑ 61.9 ns per loop (mean ยฑ std. dev. of 7 runs, 100000 loops each)
In [17]: timeit 1<<4096
106 ns ยฑ 0.691 ns per loop (mean ยฑ std. dev. of 7 runs, 10000000 loops each)
o, nevermind then
still a fairly trivial op on reasonable numbers
You're right, you can't begin a numeric literal with a decimal point in Ada.
Cool
@brave badger so you will be able to use Haskell as the scripting language for my 2D/3D game engine and app toolkit
@brave badger this is what the GUI looks like:
Well I'm not really as invested in game dev as much as I am with theory and such ๐, but I'm looking forward to it nonetheless
it isn't just for games, it is for ordinary apps too; anything that has a GUI
I've been working on it for nearly six years and it is reaching a good level of maturity: I created this chess game with AI from scratch in two weeks: https://www.youtube.com/watch?v=t4c-GX1_WnI
strange choice of colors
I think they look rather pleasant: gold is white and silver is black
although I need to make the silver look more silvery rather than whiteish
but obviously I will add the ability to customize colours, pieces and have a traditional default
I think this is correct for slice ๐
o_O
the biggest difference is not that -- it's that haskell is lazy
plus the type system
well, yeah
and im pretty sure thats not what "pure" means
PureScript also separates pure code from impure code, but interoperates with JavaScript very smoothly
(because it's strict, not lazy)
Yeah this does seem like an interesting problem.
@grave jolt you mentioned Brainfuck yesterday: I will be providing a brainfuck implementation too: how that will interact with other languages will be interesting
are you going to write the bf implementation in bf?
would be cool
you might as well do it if you have the skill to build a universal turing machine
@silk pawn no. I am writing brainfuck in neos
sad
question:
so python will constant fold this:
number_set = {0, 1, 2, 3}
but will it constant fold this?
number_set = set()
number_set.add(0)
number_set.add(1)
number_set.add(2)
number_set.add(3)
wondering if the peephole/ast optimizer is smart enough for the second example basically
nvm, forgot that it won't fold sets because they can be modified
python will not constant fold the above
it won't fold either?
or it won't fold the second
oh wait im dumb
i used a set not a frozenset
smh me
ok sorry
!e
@silk pawn it will fold a set into a frozenset in certain cases (where it knows that it won't be changed)
import dis
def f(x):
return x in {0, 1, 2, 3}
dis.dis(f)
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | 4 0 LOAD_FAST 0 (x)
002 | 2 LOAD_CONST 1 (frozenset({0, 1, 2, 3}))
003 | 4 CONTAINS_OP 0
004 | 6 RETURN_VALUE
you got constant folding for free in neos as part of semantic concept folding
it's interesting that CPython "constant-fold" a set literal into a frozenset object.
yeah, I was surprised
it also does this with list literals
!e
import dis
def f(x):
return x in [0, 1, 2, 3]
dis.dis(f)
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | 4 0 LOAD_FAST 0 (x)
002 | 2 LOAD_CONST 1 ((0, 1, 2, 3))
003 | 4 CONTAINS_OP 0
004 | 6 RETURN_VALUE
yep
cool
here it can't turn it into a frozenset, because here order of comparison is defined
except the order of comparison doesn't matter, it's just a boolean result.
It's also surprising that CPython doesn't turn {*()} (empty set literal) into one instruction.
That would make it around twice as fast: <#internals-and-peps message> (taking into account the overhead of a function call)
the comparison could have a side effect, however contrived such a case would be
@flat gazelle if the comparison could have a side effect, it wouldn't have been "folded" at all.
but CPython can't know if it has a side effect
because x doesn't have to be an integer
Also, if x is not hashable, searching in a set would raise an error.
oh wait, the x can't be a custom object
wdym?
since a global load is non-deterministic, and if it is a local, it can't be in a constant
and I don't think there is a third option
x is an argument to f, it could be anything.
I wonder how hard it is to make a pure-python bytecode optimizer that trusts typehints...
LOL
sending a value to a generator is faster than calling a Python function?
right
well, there is a catch -- if the generator fails, you have to somehow restart it
alright, so that might be a... possible optimization lol
If a function takes a single positional-only argument
exception problem solved ๐
well, except when you pass double as an argument to be stored and called later...
Question - why Python doesn't utilise Ellipsis in its standard lib?
where would it use it?
Just an example - functools.partial(func, 1, ... , 2)
and what would that mean? 1 is the first arg, and 2 is the last, and the middle args are still to be supplied?
Yes. That's from the top of my head, I haven't really thought it through.
It's just we have defined syntax, but It's not used. It's like if we had square brackets, but only used normal ones. Feels weird, like a placeholder for something.
@severe lichen there is syntax in Python specifically to be used by libraries like numpy. Ellipsis is one of them. Also @ for matrix multiplication.
@severe lichen ... is used in type annotations, e.g. Callable[..., int] or Tuple[str, ...]
that partial example sounds like a good idea - someone should propose it ๐
to a partial, or to partial?
to partial
partial(func, 1, ..., 2) now means (roughly) lambda *args, **kwargs: func(1, ..., 2, *args, **kwargs)
ever seen anyone do that?
Nope.
Well, I haven't seen a lot of code, so that's an argument from a false authority.
But still, it's a breaking change
not to say that it shouldn't be considered, of course
it is, but there are breaking changes all the time.
Hey, let's make an optional kwarg substitutes_ellipsis with default False, so it would be backwards compatible! What could go wrong?
If I have a function like this
def fn():
x: int = 1
return x
is there any way to inspect the function with typing and determine which hints have been applied to what names?
(aside from the function signature)
@uncut sage Only through ast, I suppose.
AFAIK the annotations are completely erased in function bodies at runtime
ast, that's what I thought.
I'm working on something that uses dis, so that may be too many steps down.
(otherwise, when would they be computed? when the function is created -- that's slightly confusing. when the function is called -- that's potentially a lot of overhead)
I'm actually contemplating a different method to do what I had in mind, but this is useful to know
I'm actually creating a decorator that takes in a function, disassembles the bytecode, and transforms that into assembly (sorta-kinda)
i have encountered a moral dilemma (and a serious case of bikeshedding) that has bothered me for quite a long time :D i have a class which should implement the basic arithmetic operators (__add__, __sub__, __mul__, etc), some of which have very similar code in common. which of the following options seem like the best way to do this?
-
defining
__add__and__sub__separately using very very similar code in each one (with only difference being the use of-instead of+in their relatively lengthy definitions, for example). -
defining
__sub__(self, other)by using the other defined operations to simplify it, such asself + (-1 ร other). this would produce the correct result without duplicated code. however, the use of multiple operations (multiplication and addition) to define a single, simple operation isn't very intuitive or efficient. furthermore, ifotherdoes not support integer multiplication in that example, then__sub__would raise aTypeErrorrelating to the multiplication by -1 there, which isn't an intuitive error message. -
writing a helper method that does the common operations of code for the two similar methods. this would probably be called from each of the
__add__and__sub__methods, and perhaps given a function in theoperatormodule to define which operation should be done between the operands. i'm not sure if i explained this option well at all, but it seems like an "ideal" solution which also feels unnecessarily complex.
any thoughts would be nice, even if it's just to tell me to stop thinking about the bike shed here haha (also hello i haven't spoken here in a while hi!)
oh hi juainter
I would pick 2, and inline it (pick 1) if it's slow
this may be a usecase for exec
for op, meth in [('-', '__sub__'), ('+', '__add__')]:
exec(
f"""def {meth}(self, other):
return self.val {op} other.val"""
)
this adds another direction to the moral dilemma hahaha
but it's certainly interesting, that's for sure.
I'd pick 3, I think.
i like 3 also
3 is nice, yeah.
or define helpers methods such that the meat of the logic has been separated into the helper, and the + or - or * or / would remain in the __add__ or __sub__ or __mul__ or __div__
if the long function can be refactored into a bunch of stuff, then a call to a + b, then another bunch of stuff, you can refactor "a bunch of stuff" and "another bunch of stuff" into helper methods that are used by all operators.
yeah that's a decent idea. not really applicable to my specific use-case, but still a good thought.
i think i will go for option 3 even though it seems a little overkill.
okay yeah, thanks for your thoughts everyone ^^
Definitely. in fact, it's been done: PyPy
PyPy has a JIT, so it can run much faster than traditional Python
average is said to be about 4x, but certain corner cases can be dozens of times faster (or a few times slower)
JIT is a way to get the speed benefits of compilation in an interpreter
It essentially compiles some sections of code it detects as slow and then uses the compiled code instead of the interpreted code
PyPy is a tracing Jit compiler
so it monitors / counts the amount of executions a piece of code goes through
if you want to know exactly how it works they wrote an entire paper on the thing https://www3.hhu.de/stups/downloads/pdf/BoCuFiRi09_246.pdf
Anyone around here familiar with running pytest with parallelism?
My tests use a database, but I want to set it up once. My threads are setting everything up 10+ times and they're starting up like 20 docker containers at a time.
I just need one.
This channel is more about the Python language itself - this question would fit in either #async-and-concurrency or #unit-testing - the latter is probably the place to try first.
I'll go there, thanks
Hey i have learned the basics of python. Now I want to learn about django and flask. Can anyone suggest a good source from where i can start learning.
tuple ๐
Django has tutorials in their doc pages
Flask has that too but theres also the flask megatutorial by mister miguel grinberg
Thank you
does it correctly treat one-element tuples like (42,)?
I believe so
lines 870 and 876
I cannot test the grammar until I have defined enough of it so that I can parse a simple program
if there are still undefined elements in the schema then compilation cannot proceed
i would have started with a subset and made it runnable before translating the entire grammar. isn't it kind of unsatifsying?
the gammar isn't simple enough for me to do that; print("hello") requires lots of elements to be defined
string literals, names, function calls with positional arguments
for runtime -- name lookup, function calls and constants
sure, but not slices or list comprehensions
slices and tuples are in the middle of the grammar required for print("hello") to work
I believe
wouldn't it be better if a tool that allows you to create a scripting language let you develop it incrementally?
You have numbers and tuples, and (1,) is a complete, simple program.
it depends how the grammar is defined
I want to make my grammar match the official python grammar as closely as possible
and I don't want to partially define elements either
so defining atom requires me to define everything in atom
I would rather just spend the time now fully specifying the entire grammar and then start defining the semantic concepts
you do you. i would have wanted to see a simple thing implemented from start to finish, to prove out the ideas.
I can define the semantic concepts separately and I don't have to do all of them upfront to be able to parse a program
we each chose "partial", but different kinds of partial.
prove out what ideas?
everything beyond the parsing.
I can do that with my reference langauge; I already have parsed complete non-trivial programs written in my reference language
right, Ned's point is that starting by parsing the full grammar is a breadth-first approach to the problem, where most people would instead choose a depth-first approach
yes, that is a cool idea. i would want to prove it out. You don't. I get it.
prove what out? I already know semantic concept folding works.
Most people would pick a subset of Python's grammar, build an interpreter that can successfully execute that subset, and then expand to progressively wider subsets, until they've implemented the entire language.
that isn't necessary with neos as I am not making a Python interpreter: the intrepreter is language agnsotic
that makes no difference. Most people would start by mapping a subset of the semantic concepts necessary to run a simple program through the language agnostic interpreter.
OK, forgot I brought it up. We have different approaches.
What I need to do is define the grammar first, please stop questioning my methods: you simply don't get the neos architecture
it doesn't cost much to be friendly to people
and the subset of the Python grammar required to do print("hello") isn't as small as you might think
@weary garden help me out here: when you paste your progress here, what kind of feedback are you looking for?
and I not asking for feedback that implies that I don't know what I am doing.
ok, what kind?
any other kind of positive feedback is welcome
I'm not sure what your target audience is...
Good job Leigh
you don't seem to understand what "positive feedback" means: valid critcism is positive feedback
you don't want help that implies you don't know what you're doing.... but if you knew what you were doing why would you ask for help?
this is valid criticism: it's hard to know how this is going if we or you can't run code.
my methods are being questioned here, I am asking for help related to Python language itself and I not asking for "help" because you think my methods are wrong
step 1): define the SYNTACTICAL grammar of the Python language
step 2): incrementally define SEMANTICS of the Python language
step 1 does not have to be done incrementally
step 1 is tedious however and the only reason to do what you suggest is to relieve bordom and get some kind of instant gratification
ok, i'm letting you know why it might be hard for us to comment intelligently.
was there some specific help you wanted with the tuple syntax?
I was looking for feedback and @grave jolt 's question was cromulent
i'm not sure what cromulent means?
appropriate
yeah I googled it it means adequate
It's unlikely that you'll get much help with the grammar, for a few different reasons. One is that you're writing it in a language that we don't know and can't read - or look at documentation to learn how to read. Another is that you're pasting screenshots of a subset of the file, depriving us of relevant context.
@weary garden can you push the work to GitHub so it's easier to see the whole file?
We can tell you that the interesting edge cases for tuple literals are that empty tuples are represented as just (), and one-tuples are 1,
such feedback the lagnauge is hard to read is useful feedback
that is useful to know @raven ridge I didn't know that is how you specific a 1-tuple
also consider tuple/set/literal unpacking, and things like (*{*(),*()},*{*(),*()}) (contrived way to make an empty tuple)
@grave jolt I am hoping I will get that for free from the grammar and associated documentaiton
definitely not from the grammar alone, but from the documentation should be doable.
no I mean if I have correctly defined the grammar and semantic concepts then the example described should just work out of the box otherwise the gramma is incomplete
that doesn't fall out of the grammar. Unpacking is entirely a semantic concept.
The grammar allows the tokens to exist in that order, but it doesn't tell you what it means. The meaning - unpacking - is a semantic concept.
indeed and all elements of the grammar will have a semantic concept attached to them
do you expect that to be one-to-one?
it will help with an example: this is math_expression from my reference langauge grammar
math.operator.add is a semantic concept rather than a grammar token
so the initial SYNTAX grammar can then be elaborated with semantic concepts as appropriate
do you expect that each grammar element corresponds to only one semantic concept?
it can be mapped to 0, 1 or many semantic concepts
line 697 associates the math.expression semantic concept with the math_expression grammar token/symbol; if that token is successfuly matched to a rule then the concept will be instantiated for later folding; bytecode is emitted during the folding process
so there can be multiple is entries for a single grammar symbol?
what determines if it's a string.utf8 or language.identifier ?
it is both
but a particular token in a program is only one of them, right?
an "identifier" is both a utf8 string and a language identifier
note that, in Python, an identifier is not necessarily a UTF-8 string.
I know I mentioned that before, but I'm not sure if you picked up on it.
well that is from my reference language
yep, I figured.
not Python
in print("hello"), print is an identifier, and "hello" is a string. Are we talking about the same things?
oh, not Python
but yes, he's talking about identifiers.
Speaking of identifiers, what's the rational behind allowing unicode names? Well, not all unicode, but e.g. cyrillic letters.
the alternative to unicode being?
it would make sense to restrict identifiers to alphanumeric characters IMO
How do I Generate 20 random integers between 100 and 1000 which are divisible by 4.
that doesn't sound very random
@silent seal ask in #python-discussion
check out #โ๏ฝhow-to-get-help @silent seal
the only reason to restrict yourself to ASCII is the limited number of keys on a keyboard
Ah
but if I live in China and want to write my program in Chinese why should I be forced to use ASCII? not everyone writes open source code in English
right, that makes sense
but 123 is an identifier?
@spark magnet look at line 55
there are no line numbers in that screenshot
sorry line 185
I'm not seeing comments in the Python grammar, but note that lines starting with # aren't always ignored, because https://docs.python.org/3/reference/lexical_analysis.html#encoding-declarations exist
which means that an identifier isn't necessarily a UTF-8 string, it could be a string in any codepage/encoding
ok, but this isn't Python right?
no
but the Python grammar will be similar as appropriate
so hopefully you are starting to see how I am mixing syntax and semantics in the same schema file
again, to my point, though: # has two different sets of semantics, and those aren't in any way captured by the grammar.
when do you expect to push the Python work to GitHub?
I will do a push when I have fully defined the syntax then I will incrementally push as I define the semantics
if you incrementally push the syntax, it will be easier for people to follow along
though it's possible that properly supporting # coding comments requires special case handling entirely. You probably need to handle those before even parsing the file, now that I think about it.
...although it would be quite inconsistent to mix two languages, since all libraries and even keywords are in English.
I'm a native Russian speaker, but I would never use cyrillic identifiers because
- I would constantly need to change the keyboard layout;
- I would constantly need to switch between two languages, and it's difficult (I write comments in English as well);
- I would constantly mix up characters that look the same or similarly (seeing ะฟ vs n is fine, but what about c vs ั?)
besides, writing in a non-English language would make the code pretty much unusable by people outside my country
Yeah since it's explicitly said to be 1-2nd line and match regex
I might do a push once I have enough defined for "hello world" (which will be when I get no more undefined reference errors parsing the schema)
if you share screenshots here, why not the whole file on GitHub?
btw, on line 197 of the last screenshot: what makes the "end" clause kick in?
there I just done a push as I had some code changes. happy? ๐
Yeah. Which makes this an interesting case - a Python interpreter that wants to support every possible Python program needs to pre-process the input file before it can even begin to parse it.
That's not obvious.
@spark magnet that is referenced externally by another element
Happy!
I will be getting the most feelings of gratification when I start emitting bytecode and executing bytecode
then feelings of depression because it's not fast enough, then business optimizing things, then feelings of hapiness when it is faster
Btw. Why gpl3
that's exactly why i would have done depth-first ๐
depth-first?
as we were discussing before. Get 2+2 working and executing first.
I forget? what you mean by depth first?
breadth-first is a complete grammar, and then start on semantics. Depth-first is a small subset of the language implemented all the way through.
well I kind of did that right at the start: I parsed a complete Python program consisting of some comments and a string literal
I just get stuck handling the python ast 
stuck? Can we help?
Think i just need to mull over handing the ast a bit more
CPython creates bytecode and can cache it to a file yes?
yes
The handing is in rust which makes traversing it a bit tedious without creating a mass of recursion and mess
I'll be doing something similar before I start work on the JIT
the language.keyword in your Python.neos file reminds me that we now have soft keywords, which I have to figure out how to deal with.
\o/
me too I guess
keywords appear to just be a string literal in the Python PEG grammar however I have to explictly associate them with language.keyword semantic concept so I can get syntax highlighting and such
@raven ridge is right, the coding comments are going to be a pain. you might have to just say you aren't going to support them.
was that to me?
just thinking out loud.
@oblique crystal GPL3 until neoGFX 1.0 is released then it will be dual GPL3/Commercial
I am using GPL3 to protect any IP I consider valuable
I was pointing it out for you, Leigh - yeah. Those are something that won't work in your model - they're semantically significant and need to be handled before the file can be parsed (but after the interpreter has started)
you mean character encoding of source files?
yep.
yeah I will have to address that in a language agnostic way anyway
the Python language represents that with a comment that must occur in the first two lines of the file, and that the interpreter must read and handle before parsing the file.
it can't be handled in a language-agnostic way - the semantics of the operation are tied to Python.
I can handle it in a language agnostic way, don't worry
it can result in the execution of arbitrary Python code.
the encoding is handled by a Python decoder, which can be registered dynamically at runtime.
anything can be language agnostic, it might only be used by one language.
if your goal really to be able to run absolutely any Python program, you'll need your import machinery (which includes importing any initial file that the interpreter is asked to start with) to support dynamically decoding the file using a Python codec after you find its path on disk, and before you parse it and compile it. The Python codec used to decode the file may have been registered by any other module that had previously been imported in the same interpreter session.
It definitely will be a lot to get right, and other languages won't be doing it the same way.
what is a "python codec"?
there's a registry of codecs by name, so you can look up the name "utf-8" and get an object capable of encoding arbitrary text strings to UTF-8, or decoding UTF-8 strings to their corresponding sequence of Unicode codepoints.
Likewise, someone can register their own codec, and once it has been registered within a session of the interpreter, it's possible to import files that use it as a coding comment.
what have these codecs got to do with source code file encoding?
they are what decode the file
so what does a source file look like that uses these codecs to decode itself?
this is a coding comment: https://github.com/nedbat/coveragepy/blob/master/tests/test_config.py (line 1)
here, it's utf-8, which is the default for python 3, but it could be any codec name.
it could be absolutely anything. The codec is responsible for decoding it to grammatically correct Unicode strings that are grammatically correct Python
https://aroberge.github.io/ideas/docs/html/lambda.html shows an example of using a coding comment to allow "ฮป" to be used as an alternative spelling of "lambda" in Python files.
interesting
this isn't a commonly used feature, but if your goal is 100% feature compatibility, it seems like it would throw a wrench in your plans.
well, it has interesting implications. Like, what does it mean to cache byte code for that file?
the AST might be different every time it's imported, depending on what other modules had previously been imported in the same interpreter session.
it's possible to construct a file c.py that parses to one AST if you import a before import c, and an entirely different thing if you import b before import c
i don't know how CPython deals with that.
I'm betting it mostly doesn't.
I am going to bed. later.
could this method here be used for redefining true/false or other keywords https://aroberge.github.io/ideas/docs/html/bytecode.html
with small modifications ofc
if so this is perfect material for #esoteric-python
I don't see why it wouldn't be possible.
y e s
this is what I'm talking about
I wonder if someone has made a library for this
eh
#bot-commands ๐
o yeah sorry
Guido is pushing the "export" idea even further - his latest formulation of it on python-ideas might give the ability for a module to have true private attributes that aren't accessible through normal Python attribute lookup.
like _dataclasses__json?
like that, if it wasn't accessible through normal Python attribute lookup ๐
ah
Hello, is anyone familiar with the matplotlib library?
@dusty pecan @tiny oar this isn't a help channel. See #โ๏ฝhow-to-get-help Furthermore, I suggest you ask your actual question when you claim your channels rather than asking if you can get help (the answer is probably yes if you're not breaking rules) or if someone knows a library.
@charred wagon Just posted in the help channel, thanks
I really hope pattern matching doesn't get undermined as just a glorified switch/case e.g. using it over if-chains or dictionaries for "simple" matches
I think pattern matching is rather an extension of destructuring, i.e. [x, *y, (z, w)] = foo
one thing I would love from patma is
match "342":
case int(a) except ValueError:
pass
case _:
a = 0
I guess you can extend my context_manager_patma, because it uses with statements
Where is this
is Guido teh Authoritay?
I hope Python Land isn't an autocracy like Linux Land: Linux is not going to end well.
I mean, GvR stepped down from his BDFL position
Looks like we're getting these new features then.
Something tells me gradually-typed, performant Python is the best possible outcome for the language, considering the current climate
Gradual typing would be nice.
@grave jolt you use Twitter? follow me! ๐
I suppose it'd be about the same relationship that TypeScript has with JavaScript, the former won't totally eclipse the other, but it sure is gaining traction
I guess you could do that with neos given you can mix different languages in the same source file
well, that's going to cause lots of complaints, I suppose... Python is a dynamically typed, easy to learn and teach language
although I don't know how the syntax of TypeScript differs to the syntax of JavaScript
Biggest issue is just de freaking dynamic typing 
TypeScript can have dynamic typing with any.
Something like that for Python would be nice.
makes performant optimizations like JIT compiling go from being fairly simple to big pain 
call it Tython ๐
the whole point of TypeScript is typed
using dynamic typing in typescript kinda defeats the purpose 
Not really. It's just an extra tool. You don't have to use it all the time.
Well, yes, just like Python. (it's just that TS has a better gradual typing system, which makes it feel more like a statically typed language than a beast with tentacles whom you must feed type spells)
somebody needs to create Tython at once! any volunteers?
Mmm its by far the biggest pull of TS, is the fact that it's statically typed
Not with the current type system i dont lol
Me! Jk, I'm not smart enough to do that.
If you want strictly typed python though you do have MyPy or PyRight i think they are that enforce type hints
I could do it I suppose: one goal of neos is to make prototyping new languages relatively quick and easy
Has type inference/checking been modeled with relational algebra anywhere?
It seems to be a natural tool to deal with overloads and such. But not sure how to fit infinite queries into that (with generics)
TypeScript was the best thing to happen to JavaScript.
^^
I think it's been thoroughly embraced right?
surely suggesting dynamic typing is non-optimal is blasphemy here? ๐
Python has proved that it could support its own weight, given all the
involved so the complaints are understandable especially with conflicts of interest taken into account
dynamic typing has its merits still
It would need to be optional to be viable to Python programmers.
Yep. Both static and dynamic typing has something going for it, or one would have died out
statically typed python would be interesting, considering how much of the standard library is, well, not that
dynamic typing is easier for beginners I suppose
Indeed.
but beginners worth their biscuits can soon outgrow it
ye, and it allows weird metaprogramming
and well, static type systems which don't get in your way are invariably complex
I have a bias towards static typing and its generally positive implications to runtime safety, but dynamic typing just speeds up the process of getting to a desired result, and that's just as invaluable
I would want something where you could do both in the same file. (Ignore the syntax errors, its a ts file.) Something like this.
I have a bias forged from mostly using one language for the last 30 years
Which is?
C++
I do like static typing for things that are hard to test and debug (frontend), as well as things that shouldn't ever error (banks), but if I just need to quickly grok something, they aren't all that useful
I don't think static typing should ever be in Python
If you want static typing you should use another language
I don't think it can be in python in a sensible way
python compilation runs arbitrary code, remember
I don't see a scenario where it would fit nicely in Python, even if it is optional
and therefore, so must type checking
Optional is a funny way of saying "messy"
I see.
gradual typing is neat
raku has that
but it doesn't give safety
just documentation
which type hints already do
I'd rather have better null or exception handling for instance, or better functional like coding
Every day I wish for null coalescence to exist
yeah, exception handling is quite poor
In python?
yeah
"Ask for forgiveness not permission" is a poor paradigm IMO
its a great paradigm, since for actually important things it is the only correct way to do so
Can you explain to me why? First time hearing that
try except is so much more verbose than if that it often feels punishing to use it
and there is no excepttry
In some cases, permission leads to race conditions. So there's very clear merit to forgiveness
Ah! The verbosity of it. Got it
Sure, exceptions still have its merit
And it is still useful if you have deeply nested calls or stuff like that
so you can't do like
try:
attr = obj.thing.another
except AtrributeError try:
attr = int(another_source)
except ValueError:
attr = 45
since you end up with insane nesting
this could be solved in patma with a try pattern of sorts
I've seen subtle bugs emerge when people tried checking if a file existed before deleting it. It was a nightmare to debug. So there eafp would have saved us a lot of pain
And yeah thanks lak, that's perfect. Yeah makes sense
also, not having to parse an int twice to see if it is correct
checking is often just as expensive as actually doing it
EAFP is generally nicer for potentially destructive operations I think?
That could be solved with having more functions like dict.get
but exceptions are a good solution
The point checks being expensive is also important. If the error path is a rarity, eafp will save time
In a sense you are still asking for forgiveness, you have just hiding the boilerplate
That's my understanding of it anyways
a try expression would be helpful
but very unpythonic in every implementation I can come up with
but honestly, a patma pattern for exceptions would do the trick for most things, though I am not sure how exactly it would look
Maybe it would have to be a new symbol to cut down on verbosity. If verbosity is the real problem.
But I'm torn, because I do love having python read off like almost English
I don't think a symbol is needed here
just some way to try something else that could also error if something errors
that doesn't involve nesting even deeper
One interesting syntaxt could be to have an inline except, something like
expression except (Exception) as default_value```but Iโm not a fan of this, and `as` is a poor choice of word here
Hey please tell me if I can ask for open source contribution on this server somewhere
don't think that helps
since then you have this
attr = obj.thing.another except AttributeError else (int(another_source) except ValueError else 45)
which is still nesting deeper
just in an expression, not in a statement
Yes, but at least you donโt take 4 lines anymore just to catch one exception
That's true, although in terms of library design, how deep into internal code you'd have to go until you just say screw it, let it fail, and have your mostly user-facing code handle and promote those to something more proper though
lines don't matter IMO. Creating massive expressions to avoid multiline statements seems pretty invariably bad in python
except Except as e is a good solution but it feels penalizing when used at large
Maybe I just can't be bothered 
I've seen people primarily oppose "exceptions" (EAFP) and "first checking it, then accessing it" (LBYL). LBYL leads to obvious problems, with various examples like filesystems or databases. But it's a false dichotomy -- there are also "error values", which are the best of both worlds, because:
- They force you to account for the error cases (given that you e.g. use a typechecker)
- They don't allow confusing control flow -- control flow is the same as the rest of the things (classes, functions, generators, coroutines, conditionals,, loops,
matchetc.). Exceptions can act likegotos on coke - They aren't prone to race conditions (unlike LBYL)
Alright, maybe the line count is a bad metric, but a try/except still takes a lot of place and is quite verbose
ye, but converting it to an expression is not the solution
return value based error handling has its merits yeah
but I feel like it's far too late to switch python to that
Returning exceptions like in C or Rust sounds like a poor idea
python is statement based
and I really doubt it can be better than say kotlin at being kotlin
I havenโt done a lot of Rust, and Iโm already tired of doing .unwrap everywhere
exceptions should never be checked for; they are a result of failure and if implemented properly have no cost if the exception isn't thrown
Failures are part of an application
at the same time, nice exception handling is hard
which is why even raku fails at it miserably
it is a solved problem tho
it really isn't. CPP exception handling is also quite poor, there has been direction towards monadic error handling there because of that.
Well, the worst part is that some errors are reported as values, and some as exceptions. E.g. dict.get is used as an alternative to dict[k], and then there are functions on lists, etc.
Error values are sometimes useful when you need to account for an error inside of an expression. So given that python is statement-based, you have to resort to making more statements if with some new change an expression can produce an error. Or making silly helper functions like
def pop_or(xs: list[T], default: T) -> T:
if not xs:
return default
return xs.pop()
Exceptions are one of the least solved problem of language design IMO
yeah
disagree ๐ C++ exception handling is fine and has no cost if the exception isn't thrown
And that too Only when tightly coupled to languages with certain semantics at best. Semantics that don't generalise.
I donโt think you can have except blocks without any cost
you can
You have to set it up at some point
well there is always the cost of larger executables I suppose which could potentially have a CPU cache overhead
there are common lisp conditions which work reasonably well for various tasks, but they are also far more complex than just plain old stack unwrapping exceptions
Having the liberty to model failures declaratively is both nice and meh at the same time
It is good when you want it
Sometimes you just want to do something and let it die out if it fails
Having the short-circuiting behaviour done for you is the nice thing about Haskell's Either type, which is just Result, any one of these operations can fail and client code is really the only cog responsible for collapsing the computation into an observable result:
-- Any one of these operations can fail
parseCodeBlock :: Parser Markdown
parseCodeBlock = do
_ <- string "\`\`\`"
language <- regex ".+" <* char '\n'
code <- manyTill (regex ".+\\n") (string "\`\`\`")
pure $ CodeBlock language (List.foldl (<>) "" code)
-- But it's ultimately the resposibility
-- of client code to handle the failure
-- appropriately
main :: Effect Unit
main = do
codeBlock <- readFile "README.md"
case runParser parseMarkdown codeBlock of
Left err -> log err
Right code -> log code
There is certainly some cost, and it has to do with some optimization, you can see how slow move constructors or move assignments are without noexcept especially with STL containers.
@limpid marten https://godbolt.org/z/TffK9T
some minor differences for -O3, not much difference at all with no optimizations
but getting the compiler to do what you want from a benchmarking point of view with optimisation is always tricky
There are languages that use exceptions as a way of alerting other code of various conditions (ie most Java code)
@pliant tusk I wasn't referring to catching exceptions: I was referring to how exceptions are thrown in the first place.
You can't really have one without the other?
for example you should not check if a file exists and then throw an exception, rather you should attempt to open the file and then throw because the open failed; this is mainly a concern for library implementors but is also something to bear in mind when throwing exceptions in app code
I am personally not a fan of using exceptions to unwind the stack, if you do that you probably have too much nested code
of course I am not suggesting that you shouldn't catch exceptions; I wasn't suggesting that.
@undone hare disagree: how much is "too much"
When you have too much to refactor and you need to use an exception to move up a few frames
What about situations that I (as the library maker) know will fail/cause issues. Or places where you want to raise different kinds of exceptions to show what went wrong
โToo muchโ is when refactoring isnโt an option IMO
no; totally disagree. exceptions are great; they are superior to checking error codes with hundreds of if statements all over the shop
you should have lots of throws but very few catches if you are doing it right
but I am not yet familiar with how exceptions are handled in Python, I am speaking from the point of view of C++.
def get_contents(file_name_user_input):
try:
with open(file_name_user_input) as f:
return f.read()
except FileNotFoundError:
raise ValueError('File Not Found!')
``````py
def get_contents(file_name_user_input):
if file_name_user_input not in os.listdir():
raise ValueError('File Not Found!')
with open(file_name_user_input) as f:
return f.read()```
@weary garden are you saying that the first function is superior to the second?
cause if you wait for open to fail, then you have to catch that exception to raise your own
The former should use from None
Thatโs one of the thing I donโt like about exceptions, but it makes sense
the second has a race condition in it
I don't have a fully formed view on this as far as Python is concerned however my Python implementation will have a C++ bent as far as how exceptions work and perform are concerned
why isnt that is the default for raised exceptions (nevermind just remembered what from None does)
and yea ik was a hypothetical
That wonโt be a Python implementation then
it will be
What do you mean?
it will be 100% compatible with pure Python
If you modify the semantics I donโt forsee how that can be 100% compatible
I am not modifying the semantics
and yeah, I would argue the first is more python
https://godbolt.org/z/6nc73a
You can see how with noexcept the compiler can decide to use a move instead of a copy.
the main reason to check ahead of time is for nicer errors in libraries
to be fair, the functions do 2 different things
@limpid marten true
library_function takes str as its first argument is more helpful than bytes has no attribute encode
@limpid marten but that is not due to the language itself but to how std::vector is designed; but yeah, I agree with your point.
Pretty small stuff though! ๐
Genuine question about this: if you have a lot of failures, isnโt the latter faster?
(2 is happy, 50 is sad)
What do you mean by 'C++ bent'? Zero overhead exception handling?
Yes; in general neos is language agnostic so for the default exception semantic concepts I will be implmenting them in a similar fashion
however if I need Python-specific semantic concepts I will add those too (after sighing)
however even Python-speficic semantics will be formulated in a language agnostic way
i think you will find there are a ton of python specific semantics
I don't think cpp exceptions have tracebacks you can look at from code.
that remains to be seen
remember I am not reimplementing CPython, I am implementing the Python language
the python language has a lot of semantics not found in other languages
well zero-cost exceptions are also something that is been proposed by Mark on his faster CPython proposal, so I'd assume a proper implementation is possible without changing any semantics
The level of introspection in Python makes it almost impossible to mix with other languages
is there a link to that proposal?
thanks
it is easier since you don't need os._getframe and inspect and bytecode. Not sure if ast is part of the standard though.
@undone hare tracebacks will NOT look the same as CPython tracebacks
why not though?
Might be worth it to look at other Pythons that aren't CPython to see what compromises they had to make
wont that confuse users?
once the python source code has been converted to bytecode any knowledge that it is python will be lost.
that means you'll have problems with sys.settrace, won't it?
https://docs.python.org/3/library/inspect.html seems really painful in a language agnostic way
and things like compile,eval, and exec wont work
eval will work
and sys.excepthook doesn't seem too painless either
but it's not all required, right? e.g. stack frames
are you going to compile the python at runtime?
The major problems that I see on inspect seem to be stack related, which are implementation-detail
ah, nice
I will support runtime compilation, yes
then why not support compile and exec then?
If you can implement 2 major dynamic languages on the same VM where they'd use the same bytecode and the same interpreter, agnostically, then it truly will be an amazing experiment
though for now it seems more about ideas rather than actual work (if I am not missing something?)
I don't know what they do yet, but from what I guess they do there is no reason I cannot support them too
Eval could, but I don't see how sys.settrace could. The contract of that is a hook function runs for each line of Python code that is executed. I don't see how you can possibly support that without knowing where lines of Python code are in the multi language bytecode
doesn't graalVM already do that to an extent.
to an extent, though it is not exactly that 'agnostic'
Groovy & Clojure? ๐
it is completely language agnostic
https://github.com/i42output/neos i believe this is the github for it
well, the architecture is completely language agnostic
oh, does it work already?
afaik no, it seems to be mostly configs
I am still defining the Python grammar
not true
a lot of work has been done already
I donโt get how you can have on interpreter doing many languages
however as far as Python is concerned I am still writing the grammar
well, I get how you can do it, I just canโt get how you can follow 100% of the specs
in the same way other non-CPython implementations do I guess
Following 100% of the specs isn't that hard. Doing it and winding up with something that isn't approximately equally slow is.
non-CPython implementations follows 100% of the specs, but only one language at the time
by the way, have you seen https://docs.python.org/3/reference/ ?
same way wasm works
of course
same universal bytecode that many languages target
sys.settrace is an example of this: a place where a dynamic feature of the language makes lots of obvious optimizations impossible, because they'd change user-observable behavior
Well, wasm is a target platform isnโt it
WASM is just a bytecode specification
Your CPU executes lots of languages.
just made with sandboxing in mind
Yeah I mean, a language isnโt a bytecode spec
its the same as neos i imagine because neos is just compiling multiple languages into the same bytecode
when you compile a language for WASM you target the bytecode instructions and then compile that with a wasm compatible compiler
neos architecture is such that a supported language only exists as an input schema file which describes that langauge's syntax and semantics.
ok but how?
Which seems like it will make sys.settrace impossible.
this is why the knowledge of it being python disappears once converted to bytecode .. neos is language agnostic.
But then Python hook functions that run once per line of Python code can't work.
what would a AST of that look like 
I am not yet familiar with Python hook functions; I will get around to them at some point
Alright, so that would be lcc, Leighโs compiler collection, but targeting only one backend? Sounds interesting
not
neos is not like gcc; front ends are compiled whereas neos frontends are dynamic
i ask again: but how?
Tbh i think the best way to approach a change in runtime semantics for people who are soused to the Cpython semantics is to treat it like a Python 4
Yeah I mean, despite the impl details
Trying to emulate the Cpython semantics basically takes away every chance for optimizations and design changes
Python 3 as a language is pretty locked to the Cpython way
cython go brr?
Cython isn't magically quicker
well yes but actually no
Seems unreasonable not to get around to them now, considering that, from the point of view of someone who has been listening to your plans and trying to help, they seem to be fundamentally impossible to support with your proposed model, and learning about then just requires reading 10 paragraphs that I linked to above.
Or just accepting my one line summary: they allow users to dynamically, at runtime, register a callback which will be called once per line of Python code that is executed, saying what line has been reached.
I would probably start with simpler languages like scheme, smalltalk and lua, just to see how well it works for more languages at once
They're used to implement things like coverage analysis tools and debuggers.
neos accepts a shema file which describes the langauge syntax; syntactical elements in that schema can be associated with one or more semantic concepts which are defined in extensible semantic concept library plugins; compilation involves "folding" semantic concepts instantiated during parsing source code; when this folding happens bytecode is emitted. this all happens at runtime however of course bytecode can be cached and I plan on adding a JIT to convert bytecode to machine code.
Good old lua, the language with probably the most powerful JIT ever 
Or like... brainfuck
or is it already implemented?
BF isn't that interesting
scheme, lua and smalltalk all have entirely different ways of modelling data
scheme uses heterogenous arrays with accessor functions, lua uses pseudo-oop very similar to JS, and smalltalk is its own thing which I do not know how to summrize in a single line. How those interact in a single runtime would be quite interesting to see
i could perhaps see something like this working okay on a per-function basis with limited argument/return types to things that most languages can represent
the ability to mix different languages in the same translation unit or program is not a primary functional requirement merely a side effect of the neos architecture: if two semantic concepts from different languages cannot fold then a syntax error will result
will neos have a SQL implementation?
probably
Is SQL even turing complete? ๐
sure
there is a specific operation you can recurse, so yes
well, I don't know about the standard SQL, i don't have the Book
How can you fit a database engine and Python specific VM in the same backend
the will be an SQL semantic concept plugin which will interface with my toolkit's RDBMS
do you have any ETA's for this project?
I hope to have a working Python implementation in 3 months time; adding new languages after that will be a lot less work as I anticipate there will be a lot of overlap of semantic concepts
be sure to ping me once its working, i would love to try a small library i worked on a bunch that im quite sure will just break entirely
@finite sparrow https://neos.dev
neos Universal Compiler and Bytecode JIT
it is open source
open source is not the same as me remembering in 3 months ยฏ_(ใ)_/ยฏ
!remind 3m #internals-and-peps message
Your reminder will arrive in 3 months!
I cannot gaurantee that I will remember to ping you in 3 months ๐
I envy you folks who have time to work in oss ๐คท
OSS is fun!
never too late to start
It's not about starting. It's about having time
I have two? hours a night for myself outside of my work and my family, it usually ends up being spent on entertainment so I feel like I have a break away from working.
Some people make time for it because it's something they enjoy, I don't think anyone would blame you if you wanted to leave work at work and enjoy your free time the way you like.
that's unsurprising
Seems like a function call with extra steps.
it would've made it possible to create partial functions with [] though, which seems quite neat
if you curse the function object that is
but yeah, the confusion of it doesn't seem worth the minimal benefit
I like how much they explain in the rejection, it's really well thought out.