Guns have only one purpose: physical combat. Either commit it, or, hopefully, prevent it.
Blades and encryption main purposes are not physical combat. Blades are mostly use for cutting material we use in our daily life, encryption is mainly use to hide communications.
I don't agree with Brazil move, mind you. Flippers are not dangerous to the point I would consider seizing them a priority.
This premise is not true. But I agree, it's generally ignorance about a tool, weather it's firearms or radio, that leads to people and so governments, making false claims and so taking stupid regulatory actions.
It is really. You can use a gun as a doorstop or a paperweight, but it wasn't designed to that end. It's designed to deliver massive force to a small target at range and though that could be an object (eg in a target shooting competition), the intended target is usually an animal or person. Please don't insult people's intelligence with semantic games.
It's understandable that most people don't have the lived experience to realize that firearms are mostly for recreation. Most people live in high population density areas where firearms discharge is not allowed or feasible. But for most firearms uses the vast majority of use, and indeed the marketing by the companies that manufacture them, is about the recreational aspect, not shooting people or animals. There's certainly marketing and intent towards hunting but those are .308 rifles and larger calibres explicitly designed for it and they are not the majority of the market.
Many people use firearms for recreation, and I agree that they are great fun. They are designed to put force on a target at range. If you only care about the recreation aspects, you'll be equally happy with a paintball or BB gun.
I have paintball and pellet guns and I can assure you while they are fun it is not the same. Although high calibre (.30) precompressed pneumatic air rifles are approaching the capabilities and fun of combustion propellant firearms pretty rapidly these days. And as a plus you can fire them full auto and with noise mitigation attachments without the legal worries of combustion firearms.
I'm pretty sure the vast majority of gun owners have never actually shot anyone. More common uses are: training, hunting, collecting, and plain old having fun shooting things.
I used to be pretty anti-gun, but the 2020 home protests and Ukrainians initially training with wood guns changed that.
>I'm pretty sure the vast majority of gun owners have never actually shot anyone. More common uses are: training, hunting, collecting, and plain old having fun shooting things.
You're confusing use with purpose as if to imply the utility of firearms as tools to commit violence is merely arbitrary, rather than specific to their design. Which is weird because your second sentence makes it clear you know otherwise.
Setting aside that hunting is physical combat, the purpose of guns is not to be collected, or to shoot inanimate targets. The founding fathers didn't create the Second Amendment to protect the right of the people to keep and bear arms against watermelons on stumps. Guns may have multiple uses, but their purpose is combat.
I'm not exactly on this trend, but I noticed something going into that direction:
15 years ago, I wanted the latest everything. Now I usually want the latest minus one. Python 3.11 is out? It's finally time to use 3.10. The new phone model is ready? Let me buy the one from last year.
Because it's almost as good, but a lot more reliable.
You get all the patches, all the user report, all the ecosystem support that has accumulated since then. And this has a LOT of value.
I saw this happen in myself too. I think it has to do with experiencing things as a consumer first(the "ooh shinys") and then only later being able to work through how I'm actually using the tool towards a goal.
A lot of tasks that look like they need a computer in the loop, are actually a tiny layer of tech on top of a more traditional skillset. That is, you would actually be more capable of using the tech well by studying and planning it on paper and walking in the proverbial "recording studio" practiced and prepared, than by getting a device and expecting to be hands-on with it for hours and hours every day. This analogy works for music, for visual art, for writing, for programming, and many other tasks.
The cases where you can get a lot out of being hands-on tend to be artifacts of incidental incentive structures, because so much of computing is just an abstract UI to process and edit data you already have and publish the results, vs being an more intrinsic experience - it's supposed to speed you up, not make you dwell on every decision. Staying hands-on with the machine creates incentives to polish things mindlessly, because it will never say "no" to one more layer of processing, and it will always say "yes" to your requests to keep previous versions around.
Going traditional cuts out all the fluff - you have to put in ongoing effort to support a traditional workflow, so you automatically drop your level of polish to what the task calls for. It makes you think about handling information as a performance art, instead of an idealized production process. And when you bring the computer in on top of that, it focuses you around making basic adjustments and enhancements, instead of mitigating the need for a performative approach altogether.
One's own values may shift over time. Personally, I'm still as much a fan of bleeding edge[0] as when I was a young'un.
It's just personal preference and it's fine. The weird thing is making a big deal of it, IMO.
[0] As is tradition, I must mention that I do run Arch Linux, but I'm not on the 'testing' repositories... but I'm not sure I'd ever want to be that bleeding edge, even in my youth :)
A couple weeks ago I realized I was still running the previous version of MacOS and I honestly don't want to put any effort into upgrading. It works fine right now. What a weird departure when I used to want to upgrade on day 1 and had to consciously wait two weeks for the big bugs to be worked out.
Apple has advantages. And everything comes with tradeoffs.
I don't use Apple's hardware and software anymore. Thats my position. I won't take those tradeoffs. Works for me TM.
Others use Apple's hardware and software. It works for them.
I own enough personal and professional hardware and boatloads of software, on owned hardware and in the cloud, that has nothing to do with Apple. Clearly there's competition.
Also I can generally pick up the previous generation used at a discount as the new stock is about to come in. This is especially good on big ticket items that people seem to crave having the newest version of. i.e phones, TVs, computers.
If you code in Python, your probably should use the language as much as possible and avoid calling shell commands.
E.G:
- manipulate the file system with pathlib
- do hashes with hashlib
- zip with zipfile
- set error code with sys.exit
- use os.environ for env vars
- print to stderr with print(..., file=...)
- sometimes you'll need to install lib. Like, if you want to manipulate a git repo, instead of calling the git command, use gitpython (https://gitpython.readthedocs.io/en/stable/)
But if you don't feel like installing a too many libs, or just really want to call commands because you know them well, then the "sh" lib is going to make things smoother:
Also, enjoy the fact Python comes with argparse to parse script arguments (or if you feel like installing stuff, use typer). It sucks to do it in bash .
If what you need is more build oriented, like something to replace "make", then I would instead recommend "doit":
It's the only task runner that I haven't run away from yet.
Remember to always to everything in a venv. But you can have a giant venv for all the scripts, and just she-bang the venv python executable so that it's transparent. Things don't have to be difficult.
Finally, sometimes it's just easier to do things in ipython directly. Indeed, with a good PYTHONSTARTUP script, you don't have to import everything, you get superb completion+help, and you can call any bash command by just doing "!cmd". In fact, the result can be store in a python variable. Also you can set autocall so that you don't have to write parenthesis in simple function calls.
One reason is that "&" is nestable, but ownership is just ownership.
Currently the types are:
owned T T
ref of T &T
ref of ref of T &&T
You're suggesting that instead you skip the "&" and write some sigil for owned types, say "@":
owned T @T
ref of T T
ref of ref of T ???
How do you write the type "ref of ref of T"?
On its own this isn't a super compelling argument, because "&&T" is an unusual type that one doesn't normally use. But it hints at the fact that "&" is a modifier. The stronger but less pithy version of this argument is that if you have a type parameter "T" it's essential that it can be instantiated as "T=&U" for some "U".
EDIT: come to think of it, you don't often write "&&T", but it is commonly used. If you `println!("{}", x)` where "x" is a reference, the "println!" macro also takes a reference and you get a "&&" type.
> come to think of it, you don't often write "&&T", but it is commonly used. If you `println!("{}", x)` where "x" is a reference, the "println!" macro also takes a reference and you get a "&&" type.
Yup, i see them all the time in iterators too. Eg `foos.iter().filter(|t| ..` `t` is `&&Foo` in that example, iirc. Not that you usually see it though, due to closures obscuring types.
I suspect you're not imagining all the places this would touch the language. For example:
- Does "i32" mean an integer or a reference to an integer? You almost always want it to be an integer, so maybe we carve out an exception for small primitive types, that they don't get an implicit "&".
- Likewise some library-defined types like "Rc<T>". "Rc<T>" is the way you store a ref-counted T. So you usually want "Rc<T>" instead of "&Rc<T>". Is there an exception for this type, too, or do you always have to write "@Rc<T>"? It's defined in the standard library, so if it gets an exception than there has to be a language mechanism for "types that should not have an implicit &".
- The ".next()" method on iterators has the type signature "next(&mut self) -> Option<T>", where "T" is the type of the iterator's elements. Under your proposal, you'd write "next(&mut self) -> Option<@T>". If "T=&str", then you're returning an "Option<@&str>". Which has to be equal to "Option<&str>" or else everything breaks, but that might not be super intuitive to programmers.
That last one's the most important, though I don't know how to explain it clearly. If you have a type parameter "T", then "T" does not mean owned T. It means "T", whatever "T" is. If "T" is a reference, then it's a reference. And if you have a type parameter "T" then "&T" means a reference to "T" whatever "T" is. If "T" is itself a reference, then "&T" is a reference to a reference.
Ooh that's a fun question. I think it comes from reusing the C/C++ notation for references (https://stackoverflow.com/a/2094715/2242866). But I have no idea where the original idea for using those characters came from.
There's one other thing in Rust that would be kind of difficult if passing a reference were the default, rather than the owned value. Rust has implicit returns so the last thing at the end of a block or function is returned. If you needed to explicitly ask for ownership, you'd need to do that at the end of every function. Also, Rust will yell at you if you try to have a function return a reference to a value that's going to be dropped.
> I think it comes from reusing the C/C++ notation for references (https://stackoverflow.com/a/2094715/2242866). But I have no idea where the original idea for using those characters came from.
In C++, I think that the use of '&' came from the use of '&' in C as meaning "the address of". A reference and an address to a value are similar concepts.
Rust 0.x used to have this the other way around with an explicit `move` keyword.
It was tedious and eventually dropped. For example, it's more natural to move in assignment. `= move` is weirdly boilerplatey, `=` borrowing is unhelpful, and `=` moving without the move keyword is inconsistent.
Also the moment something is borrowed starts a lifetime scope, which is useful to know. It'd be harder to notice loan scopes of loans were implicit.
I think it's, um, borrowed from C++'s pass by value / reference syntax. To be honest I'm still a bit muddled about how &x in Rust relates to &x in C++.
Oh, so it's for performance reason: the default choice is not the easiest, the the cheapest, and they force you to be explicit about paying the price of a reference?
You listed examples of free software and non-free software.
The former is much more likely to find a home on my devices.
I've found it limiting to not use WhatsApp, but not that much. It's kind of like if I knew someone who is known to stalk people, but we also have many friends in common. Maybe some friends won't come to my party, but I'm still not letting them into my house.
Mostly correct. Browsers can block ads, trackers, Javascript libraries, and elements at will using extensions. "Native" apps for web services, such as these Electron-wrapped clients, have full access to the trackers / analytics endpoints, and more. That's a big nono.
Not only this will speed up comprehensions (which are already faster than map/filter), but it will likely solve this annoying weird edge case with the scoping of lambdas in comprehensions.
Last but not least, since it removes the additional frame that the comprensions used be wrapped in, it will fix the way you interact with them using pdb, which has always been rough thanks to this invisible indirection layer.
I assume JIT will also appreciate the change, so let's see if pypy moves on this.
Migrating to a PEG parser opened so many opportunities for Python. I never expected we would see so many good things come out of it, after years of defending LL1 to keep the reference implementation simple. E.G: the new error messages are awesome.
> Not only this will speed up comprehensions (which are already faster than map/filter)
As someone coming from Haskell I find it odd that comprehensions are prioritized over generic maps (fmaps) and traversals in Python. Not only they are more verbose syntax-wise and don't allow for partial application, they also discourage people from discovering generators, as most of the tutorials go with [] and {} brackets instead of the lazy (). At least with map() people could get acquainted with generators earlier.
> I assume JIT will also appreciate the change, so let's see if pypy moves on this.
I wonder if there's a real difference between map and comprehensions performance when it comes to JIT inlining.
Guido hates higher-order functions. Once upon a time there was map, filter and reduce as builtins. Then for Python 3, they tried to remove all three, but failed due to community pushback. reduce() did get banished however.
The argument is that making it hard to use higher-order functions discourages point-free style. "Explicit is better than implicit" is a design principle of the language.
The simple version is that higher order functions do not correspond to anything that is part of our common sense thinking. As a result people have created arbitrary terminology for it like "lambda" and "reduce". When you've mastered the terminology it may seem like a good way of doing things. But there are easy alternatives for doing the same things that DON'T require mastering that terminology.
Python has a number of guiding principles, https://en.wikipedia.org/wiki/Zen_of_Python has a list, but one of them is, "There should be one– and preferably only one –obvious way to do it." And higher order functions do not win in Guido's mind.
Separately, while the operation of higher order functions is explicit, code that makes heavy use of them tends to make behavior implicit and dependent on setup elsewhere. I have heard Guido complain about that exact style of coding. I have grudging sympathy for his view. Functional code can easily be a joy to write but a confusing nightmare to debug. And we spent more time on debugging than writing.
> The simple version is that higher order functions do not correspond to anything that is part of our common sense thinking.
and what is common sense thinking here? are you talking about python or just programming in general?
> Functional code can easily be a joy to write but a confusing nightmare to debug. And we spent more time on debugging than writing
Citations needed. I'm not sure who WE is in this context. Python is an imperative lang and doesn't even do OO that well, let alone FP. but, if you are talking about programming in general, I do find it to be much easier to hunt down bugs in languages where the design philosophy of the language favors functional programing ergonomics.
tl;dr: "For those with positive coefficients we can expect that the language is associated with a greater number of defect fixes. These languages include C, C++, Objective-C, Php, and Python. The languages Clojure, Haskell, Ruby, and Scala, all have negative coefficients implying that these languages are less likely than average to result in defect fixing commits."
> As a result people have created arbitrary terminology for it like "lambda" and "reduce".
But Python does exactly that (I'm not knocking it, terminology is important, but its all arbitrary)
In Python, we have "for" loops, we have "while" loops for lists and tuples(+ special syntax for "for" loops, when looping over a list of tuples!).
Any sufficient digging into "for loops" and their implementation, and we begin to realize it's all just iterators under the hood completely hidden from the developer, but I digress.
We have a special syntax for list comprehensions, (special syntax for nested comprehensions) that extend to ranges. There's special syntax in the form of specific statements that exist only in the context of a loop; "continue", "break", "pass", etc.
There's all the implicit state passing into the bodies of these loops, and there's no referential transparency.
"map", "reduce", and "filter" are specific and have no special constructs, no magic, it does what it says on the box. I'd argue it has a very similar mental overhead to a for loop.
The phrase "for x in y" has an immediate common sense meaning in English. What it means in Python works out to that. Sure, you find a lot of complexity under the hood when you dive into the implementation. But the whole point of programming languages is to allow the programmer to think in terms of human concepts rather than machine implementations. And the concept maps directly to one that beginning programmers already have.
By contrast I've yet to meet any non-programmer who has an intuition about what "map", "reduce", and "lambda" should mean. As great as they are as organizing concepts, they are something that programmers need to learn and gain experience with before it makes sense. For a programmer who has completely internalized the concepts, it may well be similar mental overhead to a for loop. But most programmers have NOT done so. And beginning programmers find for loops a heck of a lot easier to learn - because it corresponds to something that already makes sense to them.
As for my comment about spending more time debugging than writing, that should be obvious. As https://www.scirp.org/journal/paperinformation.aspx?paperid=... notes, about 70% of total software costs come in the maintenance phase. Therefore as developers we spend over 2x the time maintaining software rather than developing it. The actual ratio varies by project size, industry, language, tooling, developer experience and so on. But that's a pretty good average. As your link notes, the contribution due to language is real, but modest.
My comment about functional programming being hard to maintain is based on anecdotal experience. I find my own functional code easy to maintain. But others have not. And my experience picking up other people's code has been at best mixed.
Oh finally, about Python, comments like "doesn't do OO very well" usually mean "doesn't do OO like I wish it did". I find them to be highly individual opinions, and not apples to apples when you compare people.
If you want to know why Python looks the way it does, you need to get into Guido's mind. You may disagree with him, but your disagreements will not help you understand why Python looks the way it looks.
And before arguing that he's wrong to think that, remember that for several years now, Python has added more developers in a year than Clojure, Haskell, Ruby, and Scala have *COMBINED*. So while he may be wrong-headed, he's wrong-headed in a way that works for a lot of people.
(Note, I think he's wrong-headed about a lot of things.)
AFAICT Guido has softened his stance on this somewhat. The main impediment to `map()` and friends at this point is the clunky `lambda` syntax. However here we see another benefit of syntactic comprehensions over higher-order functions: comprehensions can be inspected deeply and inlined or otherwise optimized as a special case, while a stack of higher-order functions might need a more advanced bytecode compiler or JIT to apply "deforesting" and inlining.
Unfortunately, partial application doesn't work in Python, the same way it works in Haskell. If a function has 3 args, calling `f(x)` is a guaranteed runtime `TypeError`. There is functools.partial to hack it into the language for cases where you absolutely need it but overall it's bad developer experience. In fact, when I do need to partially apply `f(x, y, z)` I much prefer doing `g = lambda y, z: f(fixed_x, y, z)` because it's clearer than using functools.partial.
I don't agree that the `lambda` is clearer than `partial`. This is a matter of personal style and preference, and IMO the top priority in cases like this is consistency within the codebase.
You can also refactor partial function applications into callable classes depending on your needs, which is basically what `functools.partial` does internally anyway.
Comprehensions vs. map/filter/etc. is a style thing.
If you think in terms of an expression language that composes functions, then map and filter are more natural.
If you think in terms of a statement language with special syntax for computation expressions, then comprehensions are more natural.
Even in Racket (a scheme), idiomatic code seems to prefer the `for/thing` family of macros, which have a variety of flavors and keyword arguments to support map, filter, reduce, mapcar, etc.
So, out of curiosity: what does the PEG parser have to do with this particular PEP? It seems like this was just a somewhat inefficient (but simple) implementation choice from the start that is now being improved.
I don't know that it matters here specifically. But I think it was a kind of watershed moment in terms of how the development approach to CPython has changed.
Are you sure about the lambda scope bit? It seems to me there will still be only one loop variable, which gets re-used throughout the loop (unlike, for example, the 'do' loop in Scheme, where each turn through the loop explicitly gets new locations for all variables).