-
18 votes
-
Microsoft releases source for the version of the Linux kernel used in WSL2
16 votes -
Oregon Republican senators end walkout over carbon bill
13 votes -
The unknown Tekken god: How Arslan Ash overcame borders and legends to win Evo Japan
7 votes -
American Football - Uncomfortably Numb (2019)
10 votes -
Inside Starshot, the audacious plan to shoot tiny ships to Alpha Centauri
10 votes -
I just ran across Planetes and I love it, any similar recommendations?
I very much enjoy the "old anime" style and space-based stories. I can't believe that I had never seen Planetes before. Are there any other less well known shows like this that you might...
I very much enjoy the "old anime" style and space-based stories. I can't believe that I had never seen Planetes before. Are there any other less well known shows like this that you might recommend?
FYI: I have already seen the old standards such as Bebop, Trigun, Neon Genesis Evangelion, Mobile Suit Gundam, Ghost in Shell, Macross, and maybe a couple others. But this standalone universe of Planetes made me realize there may be a lot more out there of which I am unaware. Thanks!
10 votes -
Jake Is Writing | "The Weird and Wicked Wildlife of West Virginia" available now
6 votes -
G-20 leaders resolve to prevent exploitation of Internet for terrorism
G-20 leaders resolve to prevent exploitation of Internet for terrorism This statement was reportedly an initiative of the Australian Prime Minister.
9 votes -
Sopor Aeternus - Beautiful Thorn (1994)
5 votes -
Disney heiress calls for wealth tax: 'We have to draw a line'
10 votes -
D&D and things I made
Hey folks, we had our 3rd meet for the current campaign last night all went really well. Last time our Rogue upset everyone he met, stole everything that wasn't and was nailed down, including the...
Hey folks, we had our 3rd meet for the current campaign last night all went really well. Last time our Rogue upset everyone he met, stole everything that wasn't and was nailed down, including the nails. Then managed to get killed by an NPC that we were helping, it was amazing.
Now I wanted to get a little more creative with my character and since level 3 for Paladin is the oath level I went with Vengeance and wrote an Oath. I posted it in my last thread but will post again if anyone is interested.
Now I also wanted to have a go at making a dice bag, the first one is reversible but was too long so I made a few smaller ones. Then had the thought of making each of the guys a small bag with their names on them, each has a name longer than my leg so that failed before it started. I ended up with the initial of their first names, the Rogue wouldn't give up the name or initial so I did something different for his. The guys all loved the gifts especially the Rogue (now a Monk) these are the bags I made next thing I try will be a multi compartment job. All was done by hand because I couldn't get the sewing machine to work ...
13 votes -
Scientists successfully transfer first test tube rhino embryo
6 votes -
Awk by example
11 votes -
Madonna at sixty: The original queen of pop on aging, inspiration and why she refuses to cede control
5 votes -
Sixteen dog food brands may cause heart disease in pets, FDA warns
10 votes -
Let me speak freely: Our freedom of speech 'crisis' is culture warriors' codswallop
9 votes -
macOS Night Shift feature causes infinite loop on device when taken to the arctic circle during summer
@austinj: TIL that if you go North of the Arctic Circle in the summer and bring a MacBook with Night Shift set to be triggered by sunrise/sunset, the process will go into an infinite loop because the sun never sets...
30 votes -
My best night-time photo from Prague: City Ducks
9 votes -
Beautiful maps of the solar system’s asteroids and the topography of Mercury
6 votes -
Code Quality Tip: The importance of understanding correctness vs. accuracy.
Preface It's not uncommon for a written piece of code to be both brief and functionality correct, yet difficult to reason about. This is especially true of recursive algorithms, which can require...
Preface
It's not uncommon for a written piece of code to be both brief and functionality correct, yet difficult to reason about. This is especially true of recursive algorithms, which can require some amount of simulating the algorithm mentally (or on a whiteboard) on smaller problems to try to understand the underlying logic. The more you have to perform these manual simulations, the more difficult it becomes to track what exactly is going on at any stage of computation. It's also not uncommon that these algorithms can be made easier to reason about with relatively small changes, particularly in the way you conceptualize the solution to the problem. Our goal will be to take a brief tour into what these changes might look like and why they are effective at reducing our mental overhead.
Background
We will consider the case of the subset sum problem, which is essentially a special case of the knapsack problem where you have a finite number of each item and each item's value is equal to its weight. In short, the problem is summarized as one of the following:
-
Given a set of numbers, is there a subset whose sum is exactly equal to some target value?
-
Given a set of numbers, what is the subset whose sum is the closest to some target value without exceeding it?
For example, given the set of numbers
{1, 3, 3, 5}and a target value of9, the answer for both of those questions is{1, 3, 5}because the sum of those numbers is9. For a target value of10, however, the first question has no solution because no combination of numbers in the set{1, 3, 3, 5}produces a total of10, but the second question produces a solution of{1, 3, 5}because9is the closest value to10that those numbers can produce without going over.
A Greedy Example
We'll stick to the much simpler case of finding an exact match to our target value so we don't have to track what the highest value found so far is. To make things even simpler, we'll consider the case where all numbers are positive, non-zero integers. This problem can be solved with some naive recursion--simply try all combinations until either a solution is found or all combinations have been exhausted. While more efficient solutions exist, naive recursion is the easiest to conceptualize.
An initial assessment of the problem seems simple enough. Our solution is defined as the set of array elements whose total is equal to our target value. To achieve this, we loop through each of the elements in the array, try combinations with all of the remaining elements, and keep track of what the current total is so we can compare it to our target. If we find an exact match, we return an array containing the matching elements, otherwise we return nothing. This gives us something like the following:
function subsetSum($target_sum, $values, $total = 0) { // Base case: a total exceeding our target sum is a failure. if($total > $target_sum) { return null; } // Base case: a total matching our target sum means we've found a match. if($total == $target_sum) { return array(); } foreach($values as $index=>$value) { // Recursive case: try combining the current array element with the remaining elements. $result = subsetSum($target_sum, array_slice($values, $index + 1), $total + $value); if(!is_null($result)) { return array_merge(array($value), $result); } } return null; }
Your Scope is Leaking
This solution works. It's functionally correct and will produce a valid result every single time. From a purely functional perspective, nothing is wrong with it at all; however, it's not easy to follow what's going on despite how short the code is. If we look closely, we can tell that there are a few major problems:
-
It's not obvious at first glance whether or not the programmer is expected to provide the third argument. While a default value is provided, it's not clear if this value is only a default that should be overridden or if the value should be left untouched. This ambiguity means relying on documentation to explain the intention of the third argument, which may still be ignored by an inattentive developer.
-
The base case where a failure occurs, i.e. when the accumulated total exceeds the target sum, occurs one stack frame further into the recursion than when the total has been incremented. This forces us to consider not only the current iteration of recursion, but one additional iteration deeper in order to track the flow of execution. Ideally an iteration of recursion should be conceptually isolated from any other, limiting our mental scope to only the current iteration.
-
We're propagating an accumulating total that starts from
0and increments toward our target value, forcing us to to track two different values simultaneously. Ideally we would only track one value if possible. If we can manage that, then the ambiguity of the third argument will be eliminated along with the argument itself.
Overall, the amount of code that the programmer needs to look at and the amount of branching they need to follow manually is excessive. The function is only 22 lines long, including whitespace and comments, and yet the amount of effort it takes to ensure you're understanding the flow of execution correctly is pretty significant. This is a pretty good indicator that we probably did something wrong. Something so simple and short shouldn't take so much effort to understand.
Patching the Leak
Now that we've assessed the problems, we can see that our original solution isn't going to cut it. We have a couple of ways we could approach fixing our function: we can either attempt to translate the abstract problems into tangible solutions or we can modify the way we've conceptualized the solution. With that in mind, let's take a second crack at this problem by trying the latter.
We've tried taking a look at this problem from a top-down perspective: "given a target value, are there any elements that produce a sum exactly equal to it?" Clearly this perspective failed us. Instead, let's try flipping the equation: "given an array element, can it be summed with others to produce the target value?"
This fundamentally changes the way we can think about the problem. Previously we were hung up on the idea of keeping track of the current total sum of the elements we've encountered so far, but that approach is incompatible with the way we're thinking of this problem now. Rather than incrementing a total, we now find ourselves having to do something entirely different: if we want to know if a given array element is part of the solution, we need to first subtract the element from the problem and find out if the smaller problem has a solution. That is, to find if the element
3is part of the solution for the target sum of8, then we're really asking if3 + solutionFor(5)is valid.The new solution therefore involves looping over our array elements just as before, but this time we check if there is a solution for the target sum minus the current array element:
function subsetSum($target_sum, $values) { // Base case: the solution to the target sum of 0 is the empty set. if($target_sum === 0) { return array(); } foreach($values as $index=>$value) { // Base case: any element larger than our target sum cannot be part of the solution. if($value > $target_sum) { continue; } // Recursive case: do the remaining elements create a solution for the sub-problem? $result = subsetSum($target_sum - $value, array_slice($values, $index + 1)); if(!is_null($result)) { return array_merge(array($value), $result); } } return null; }
A Brief Review
With the changes now in place, let's compare our two functions and, more importantly, compare our new function to the problems we assessed with the original. A few brief points:
-
Both functions are the same exact length, being only 22 lines long with the same number of comments and an identical amount of whitespace.
-
Both functions touch the same number of elements and produce the same output given the same input. Apart from a change in execution order of a base case, functionality is nearly identical.
-
The new function no longer requires thinking about the scope of next iteration of recursion to determine whether or not an array element is included in the result set. The base case for exceeding the target sum now occurs prior to recursion, keeping the scope of the value comparison nearest where those values are defined.
-
The new function no longer uses a third accumulator argument, reducing the number of values to be tracked and removing the issue of ambiguity with whether or not to include the third argument in top-level calls.
-
The new function is now defined in terms of finding the solutions to increasingly smaller target sums, making it easier to determine functional correctness.
Considering all of the above, we can confidently state that the second function is easier to follow, easier to verify functional correctness for, and less confusing for anyone who needs to use it. Although the two functions are nearly identical, the second version is clearly and objectively better than the original. This is because despite both being functionally correct, the first function does a poor job at accurately defining the problem it's solving while the second function is clear and accurate in its definition.
Correct code isn't necessarily accurate code. Anyone can write code that works, but writing code that accurately defines a problem can mean the difference between understanding what you're looking at, and being completely bewildered at how, or even why, your code works in the first place.
Final Thoughts
Accurately defining a problem in code isn't easy. Sometimes you'll get it right, but more often than not you'll get it wrong on the first go, and it's only after you've had some distance from you original solution that you realize that you should've done things differently. Despite that, understanding the difference between functional correctness and accuracy gives you the opportunity to watch for obvious inaccuracies and keep them to a minimum.
In the end, even functionally correct, inaccurate code is worth more than no code at all. No amount of theory is a replacement for practical experience. The only way to get better is to mess up, assess why you messed up, and make things just a little bit better the next time around. Theory just makes that a little easier.
17 votes -
-
Boeing's 737 Max software outsourced to $9-an-hour engineers
24 votes -
The Green New Deal wants farmers to restore the land, not keep wrecking it
4 votes -
Tildee — A python library for interacting with Tildes
Update! After a few hours of struggling I managed to set up Read the docs for Tildee, it should help using the library significantly. After getting some inspiration from TAPS I thought that maybe...
Update! After a few hours of struggling I managed to set up Read the docs for Tildee, it should help using the library significantly.
After getting some inspiration from TAPS I thought that maybe I try to work on something vaguely similar on my own. And after… some? hours of coding today I came up with this: tildee.py (source)
It's a wrapper for the Tildes Public/Web API that is already used by the site internally to make it work. The obvious problem with that is that it will at one point break when this unstable API is changed. It can do basically all things a normal user can do with the notable exception of applying comment labels (because I haven't gotten around to that yet).Example of usage for a DM reply bot (result):
import sys from tildee import TildesClient import time # Initialize client and log in, 2FA isn't supported yet and will probably break in horrible ways t = TildesClient("username", "password", base_url="https://localhost:4443", verify_ssl=False) while True: # Retrieve the "unread messages" page and get a list of the conversations there unread_message_ids = t.fetch_unread_message_ids() for mid in unread_message_ids: # Access the conversation history page; this also clears the "unread" flag conversation = t.fetch_conversation(mid) # Get the text of the last message text = conversation.entries[-1].content_html # Abort if it's from the current user (I don't think this could actually happen) if conversation.entries[-1].author == t.username: break print(f"Found a message by {conversation.entries[-1].author}") # If the message contains a reference, reply in kind if "hello there" in text.lower(): print("Replying…") t.create_message(mid, f"General {conversation.entries[-1].author}! You are a bold one.") # Delay before processing next unread message time.sleep(3) # Delay before next unread check time.sleep(60)This has a lot of potential. Haven't yet figured out potential for what, but I'll take what I can get.
I'd be really grateful if someone with a little more experience than me (that's not exactly a high bar :P) could give me some pointers on the project's structure and the "API design", hence the ask tag. Other creative ideas for what to use this for are appreciated, too.47 votes -
On 'hottest day in history of France,' world told 'do not look away' as police tear-gas climate campaigners in Paris
33 votes -
M24 x Stickz - Luke Cage (2019)
3 votes -
Something About Zelda: Breath of the Wild - Animated Speedrun Parody
8 votes -
SpaceX faces daunting challenges if it’s going to win the internet space race
8 votes -
CO2 and Climate Task Force (AQ-9) [1980]
8 votes -
A system for "starred" posts on sensitive/advice topics
This was inspired by this post. I was thinking, as a platform gets bigger we're going to end up with more situations where people are asking for advice about fairly serious stuff. In some cases,...
This was inspired by this post.
I was thinking, as a platform gets bigger we're going to end up with more situations where people are asking for advice about fairly serious stuff. In some cases, that advice needs to come from experts and taking guidance from any random Joe on the street can be risky/dangerous. (For the record, I don't think the post I'm referencing is an example of this, it just got me thinking about it).
In cases like this, I think it's important that the actual good advice get some kind of clear designation that THIS is the guidance you need to take first. I notice this in communities like /r/Fitness a lot where people will post about what sound like pretty serious health concerns and you get a fair number of posts that suggest toughing it out or whatever and the more critical "You need to see a doctor" posts can kind of disappear amid the discussion. Similar things in /r/relationships where you can't always count on "This is abuse. Make arrangements to get your kids and yourself somewhere safe. . ." to be the top post.
Even in cases where the poster themselves is smart enough to take "YOU NEED TO SEE A DOCTOR" type advice to heart, not every schmuck searching the topic on Google will. To that end, it might be good to give certain posts with good, holistic advice or by a known expert some kind of visual indicator that it deserves to be taken more seriously than other posts in the thread. It wouldn't be censoring anything really, just providing a little nudge about what ought to be consulted first or taken to heart.
Now obviously it gets hard to decide how to give a post this attribute. It could possibly be awarded by the OP, though that has some obvious issues where the OP themselves might not be in a position to credibly vet the advice they're getting. We could also just do it through ranking by vote, which is the default paradigm. But like I said, it doesn't always work so well on Reddit. And the Exemplary tag is invisible to others, so that doesn't work either (and the post itself might not be worth giving up your "Exemplary" for the day besides). Moderators could do it, but there may not be enough and the skillset to be a Mod might not overlap with the skillset to know what advice a person needs in a particular situation.
I don't actually have the answers. Maybe it just comes down to creating an attribute for some users to be "wisened elders" or something and empower them to star certain posts to separate good advice from bad. It would basically be a trusted user system. It's got it's own problems, but I guess we can open the floor for other ideas. Maybe it's not a real concern. Maybe it's better addressed by tinkering with the sorting of posts.
11 votes -
Can you beat Ratchet & Clank: Up Your Arsenal with only the wrench? | VG Myths
2 votes -
How to speak Silicon Valley: Fifty-three essential tech-bro terms explained
27 votes -
Anyone else doing Plastic-Free July? What's your main area of focus?
8 votes -
Trans women and femmes speak out about being fetishized
8 votes -
Star Trek Discovery Season 2 | re:View
5 votes -
Imogen Heap - Guitar Song + Speeding Cars + Hide and Seek: NPR Tiny Desk Concert (2019)
10 votes -
Queer parenting: The beauty of the sometimes less-visible modern family
5 votes -
Andrew Yang says microphone was 'not on' at times during Democratic debate
22 votes -
3Teeth - Pumped Up Kicks (2019)
4 votes -
Björn Borg's son Leo set to make his Wimbledon debut
5 votes -
Creator of DeepNude, app that undresses photos of women, takes it offline
30 votes -
Apple cancels plans for second data center in Denmark
6 votes -
The Green New Deal wants farmers to restore the land, not keep wrecking it
11 votes -
How drag queens have sashayed their way through history
5 votes -
Brad goes farming in Hawaii | It's Alive
9 votes -
The Norwegian town of Sommarøy wants to abolish time
9 votes -
Kirkbi Invest – Legoland owner Merlin Entertainments agrees £4.8bn offer
3 votes -
Root-level Remote Command Injection in the V playground
12 votes -
MLB is making a play for popularity in Europe – but in Finland they've already made baseball their own
7 votes -
Has Wine begun to remove the need for linux software?
I started using wine in about 2013 and I remember back then it was quite patchy and only worked on some programs/games. I used to have a rule that I stuck hard to that I would not buy any games...
I started using wine in about 2013 and I remember back then it was quite patchy and only worked on some programs/games. I used to have a rule that I stuck hard to that I would not buy any games that did not have a linux version. But now in 2019 I have found that everything I have tried to run in wine has been so seamless and close to flawless that I hardly know its running in wine. I semi regularly buy games that only have windows version because I am mostly sure it will work and can get a refund if it doesn't.
What does everyone else think about this?
8 votes