Especially in an environment where you mostly interact with objects via events, I think querying an object's past sounds pretty doable. Naively we could hold on to all events ever and query for one that matches what we're talking about. Less stupidly, these past tenses are usually in forms like "if this happened recently" or "if this happened ever" which a compiler could rewrite into a variable that the relevant event sets.
So, the compiler sees "if Pacman ate a power pellet within the last ten seconds" in whatever syntax it accepts. It goes to Pacman's "eat power pellet" function and appends code to set Pacman's last-power-pellet-eaten variable, which it has to introduce. The original conditional gets rewritten in terms of timestamp comparison.
Using past tense instead of explicit state handling is actually a very interesting idea that I don't see being commonly used. Wort thinking about.
But... Event-based logic is often the source of horrendous complexity and bugs due to timing and exponential complexity of dealing with various sequence permuations. This is one of those things that I firmly believe people should be conditioned to avoid at all cost by using either functional (immutability+recursion) or logic (rules+deduction) flavors of programming. This is one of those things that's really not intuitive to get started with but provides huge benefits in the long run.
Even the basic "do this 5 times" is expressed in the same way as a set comprehension:
this_set_of_items.each do |item|
puts "hey, look at #{item}"
end
5.times do |index|
puts "look, a line!"
end $('.card').hide();
to mean "hide all cards", or $('.card.green').show();
to mean "show all green cards". It's really comfortable to think about operating on the set like this and not having to worry about looping on the individual items.From the article:
a) 1___ 2___ 3___ 4___ 5___ 6___ 7___ 8___ 9___
Thinks of them as a set or subsets of entities and operates on those, or specifies them with plurals. Example: Buy all of the books that are red.
b) 1___ 2___ 3___ 4___ 5___ 6___ 7___ 8___ 9___
Uses iteration (i.e. loop) to operate them explicitly. Example: For each book, if it is red, buy it.
In your case it looks like you are operating on each item and not on the set.
(1 to 5) foreach { _ =>
println("look, a line!")
}
That's really nothing to do with Sets.Isn't Clojure's philosophical foundation almost exactly this? Adding the dimension of time to data structures? I vaguely recall a ConTalk by Rich Hickey from the early days about it.
The 3 elements make sense even as a programmer, but of course you would need to do them yourself in your program logic and might opt for something simpler
What you described, has ever, has recently seems like classical finite state machine.
Thank you
Sounds a bit like Event Sourcing.
I can imagine logic like:
Do action "foo" if user_account has ever been in the "deactivated" state.
Rather, what I'm constantly amazed at (and maybe its because I'm working in stereotypical enterprisey environments?) is how complex, convoluted, long and hard to follow a lot of code is. So much code goes into what to a non programmer or novice would seem like a fairly simple task. And so much code is really horribly written and designed and implemented. Its very much true what your professors say about how you'll spend more time reading code than writing it. Anyways, I'm sure my perspective as both a junior dev and a late career switcher is somewhat biased, but there you have it.
It's rare that people get the chance to go back and fix up the code once they have a better understanding of the problem.
When I finally delved into Perl, Python, C, etc. and reading open source code (mostly C, mostly greenfield projects), I was flabbergasted to discover how much coding is by guess and by golly. I am genuinely unable to grasp how a person with the intelligence to master the technical details that programming requires could be so lacking in ability to elegantly conceptualize a problem domain and produce suitably organized code. I have come to wonder if it isn't a psychological inhibition. Like some people keep their desk obsessively neat but others work amid a filthy messs, not because they're too lazy to clean but because they're more comfortable that way.
Once in a while, I see a programmer demonstrating the clarity of analysis I'm accustomed to seeing in science (and even the humanities). This is the kind of programmer who will produce a shorter and clearer solution in C than the average programmer will produce in Python. It's rare, though, so I'm constantly amused/irritated by the frequently stated assumption on HN and elsewhere that programmers have superior analytical skills.
there are programmers with little analytical skills but given enough time they will end up with code doing mostly the right things... unfortunately from the out side there is no way to tell to what degree the code evolved from try and error or from true analysis...
Then there are skillful and analytical programmers who over the course of the dev cycle for a problem burn out their "analytical mana" due to simple exhaustion, external pressure or both or simply because the problem grows conceptually over their 'head-room' during the work on it... backtracking and reworking already written down code is still cumbersome, always a risk and unpleasant ('trashing something already done')
Then there often is time eroding the most clean, analytical code with every little update into a mass, unless ofc energy is spent to re-analyse and rewrite.
Then there are ofc some differences between areas in which programming is used.
'how much coding is by guess and by golly'
I hear this quite often from ppl with math, physics background etc. who are often accustomed to read expositions of ideas in math papers: presenting the final versions of the formulas.
Code quite often is more equivalent to the notes a mathematician would make and use before summarizing them into the published paper.
Those Math-Whitepapers are executed in the heads of the humans so they tend to try to keep it clean and minimal and analytical sound.
Those Code-Artefacts are executed by machines which don't care at all about such things, thus as long as the humans are satisfied with the end-results the 'inner-structure' tends to erode. Code is read more often than written but it is often only read later and by other people, so ... first things first: it has to work, right? ;)
But yea, I mostly agree that many programmers slide down into a habit of very special kind of
"reactive programming" ;)
where they try to hit the target by incrementally zeroing down on a solution reacting only on the results of the previous version of the code. Due to the action - reaction structure this tends to be quite flow-inducing and satisfactory... but the results are seldom analytically pleasing or sound.
I've done many years of programming and wrote some bigger programs from scratch by myself. Almost always the actual code is far more complicated than one would assume it should be. And it's not because it's of low quality. It happens that writing something nontrivial that works in the real world requires all the details, checks and abstractions it contains.
If you were in school recently, maybe you were lead to think that programming is an extension of math, where everything is pure, simple and provable. But it isn't - programming is much messier.
The difficult part usually isn't the restructuring itself, but understanding what the program is supposed to be doing in the first place. Fortunately, deleting code is one of the best ways to learn about what it's doing. You need some good tooling to do this safely, though.
I think it helps to separate essential complexity, due to the nature of the problem you’re trying to solve, from accidental complexity, which comes from other sources. In an ideal world, you’d represent the essential complexity as clearly and flexibly as possible, and minimise the amount of accidental complexity you put on top.
That accidental complexity can come from lots of different sources: tools that aren’t a perfect fit for what you’re trying to do, a design that isn’t as clean as it could be, an unfortunate choice of data structures of algorithms… I suspect it probably is fair to say that a lot of accidental complexity that goes into real world programs could have been avoided if, for example, more appropriate tools had been used or better design decisions had been made during development.
In one, the code started simple and evolved in place to accommodate bugs or additional use cases. Some refactoring has happened in the past, and that added some complexity to the overall project, but still not all of the abstractions were right. Further refactoring may have been attempted, but proved too involved given the value of the task at hand and the complexity the code had already acquired. The code is now more complex further raising the bar for refactoring when the next change comes along.
In the other, substantial effort went into designing the code to be flexible. It was recognized that not all use cases could be understood at the outside, and that refactoring things mid project often fails due to time constraints. A design was arrived at best on the most complete understanding of the requirements at the time, and that naturally design had a certain amount of intrinsic complexity to it as the requirements were complex. As development progressed, it was discovered that the design was not ideal for the actual requirements of the project. Plumbing was added and layers were tacked on to work around the issue.
What I conclude from this that you're damned if you do and you're damned if you don't.
Practically, I generally prefer working with code that was arrived at by the first approach. It often has a few good abstractions in along with a bunch of methods or classes that just combine too much stuff in one place. Perhaps some things are plumbed into places they shouldn't be. This can, with time and patience, be peeled apart into something a bit more manageable. By contrast, my experience with the second strategy is that it leads to a much less manageable mess where most time is spent finding the code that actual does anything. There is much more plumbing to rip out and seeming innocuous changes have far-reaching consequences.
It could be a "that's your problem, buddy". That's more likely.
How is it different from making structural engineering more accessible to non-structural engineers, dentistry more accessible to non-dentists, etc?
Take my latter question not so literally—I mean to ask what is wrong with everyone having their own profession as a result of their passions/natural talent?
Non-programmers often need to "program". For example, consider writing email filtering rules. The wording and flow could be improved with the learnings from this study. "Apply this label to this mail and all the ones like it, then archive all of those mails".
But human beings have been inventing formal notations because they end up being the right tool for the job, most of the time, to guide thought, even if the upstart cost of using them takes some work. I suspect that being afraid of formality will gradually make you lose power over the computer, and will cause unpredictable results when it isn't crystal clear where the impedance to communication and understanding with the machine lies.
I'm all for the more declarative style of programming though, even if it doesn't resemble any particular natural language specifically (remember that papers like these still have a grand Anglo bias in their implementations – imagine the sparsity of a Chinese version of these studies, and the potential difference of the results!).
What seems to be happening is people trying to figure out how to make teaching programming easier—like the guy below who works as a TA. I wasn't a TA but I did help a lot of people in school with programming and other CS assignments, and I definitely noticed lots of people in the field for the wrong reason. Either because they thought they could make a lot of money or because their parents wanted them to do it—but they had no natural interest or talent and didn't understand anything. Some of them declared many times they "hate" math or science.
Why do we have to go out of our way to teach people like this computer science principles or programming? They aren't interested in it and don't think the right way. There are many other professions and schools out there, surely most people can find what they really are cut out for, right?
And what makes you think that these potential new language features won't make it easier for experienced programmers as well? Sure, everyone will eventually get their head around iterative loops, but should we not be using the most efficient language for our brains? At the end of the day, a non intuitive concept will have inherent overhead.
I'm thinking
var output = [];
for (var i=0; i<listOfThings.length; i++) {
var thing = listOfThings[i];
var newThing = applyAction(thing);
output.push(newThing);
}
vs. listOfThings.map(thing => applyAction(thing));
and even that is a little bit iffy.Input + Generation = Output + Consumption + Accumulation
It applies to so many problem domains. They should teach it in 5th grade.
no, but it might be helpful for designing programming languages. not necessarily to make programming languages that're easier for beginners to use, but because there are two immediate entities that interact through a programming language, the computer and the programmer. so learning how humans naturally tend to formulate problems and solutions could be valuable for designing that interface.
And all dentists, at one point, were non-dentists.
non-programmers tended to define/use
- declarative event-based rules over imperative flow
- set manipulations instead of 1by1 iterative changes
- list collections instead of arrays. ability to sort implicit
- rule-based exclusions for control flow instead of complex conditionals with NOTs
- object-oriented state but no inheritance
- abstract past/future tense to describe information changing over time instead of defining state-variables
other issues
- not well specified mathematical operations
- AND used as logical OR e.g. "90 and above"
- life-like motion/action assumed instead of defined; e.g. not defining x,y location and frame-by-frame delta
However, looking at your summary, it suddenly sticks out that this issue could actually be connected with the tendency to use set manipulation. "If you score 90 and above", and I suspect many other seemingly abusive uses of "and", can turn out to be perfectly valid if you consider them as (infinite) set manipulations. However, I'm not sure which of the two explanations is closer to the actual cognitive processes behind such a phrase. Seems to me that humans are naturally comfortable with many set manipulations, while current computers require fairly elaborate abstractions in order to deal with them as sets, especially infinite. This might be one of the gnarly parts of human -> machine translation.
1. "if [you score 90] and [you score above 90]"
2. "if you score in [{90} 'and' {x: x > 90}]"
[1] is unsatisfiable. [2] is still ambiguous, as it's unclear in natural language whether 'and' is a set union or intersection.In mathematical terminology, 'and' in this countext would mean set intersection, but I don't think it's necessarily "incorrect" to have this mean set union in natural language.
To elaborate, take: C = A union B. Here are two propositions about C:
I. forall c in C. (c in A) OR (c in B)
II. (forall a in A. a in C) AND (forall b in B. b in C)
These propositions are not equivalent. [I] actually implies C is a subset of (A union B), and [II] implies that it's a superset. Note that set builder notation for C, {c: (c in A) OR (c in B)} is structurally very similar to [I].I think [II] is the interpretation of 'and' that is intended through the natural language use. It's essentially a form of set construction: I am constructing a set; it contains 90, and it contains the numbers above 90. As a set construction it also adds an implicit constraint that the new set can't contain anything not in the operands, so that resolves the superset ambiguity (it would be patently absurd in natural language to claim that 55 could be in the set "90 and above").
"90 and above" is the smallest set X satisfying both:
* 90 is in X
AND
* Above(90) is a subset of X
Another description of this set is:
An element x is in the set "90 and above" if x is 90 OR if x is in Above(90).
AND/OR are dual to each other, and it's just a matter of perspective on whether you're building up the set(OR) or constraining the set(AND).
In other words, if we could make a programming language that's more approachable to non-programmers, we might benefit everyone.
EDIT: For those who didn't read the article, I say 5th grader here because a large part of the study is actually about them. Not because I arrogantly compare people from other fields to children.
Haven't read the entire paper but...learning from something doesn't mean you need to design something 'based' on that.
The advantage of studying how people unfamiliar with a specific way to solve problems will solve that problem is actually a great technique to try to understand common patterns and approaches humans think about problem solving.
Some pattern solving strategies will be more successful than others and it is worth understanding what is common to those (especially when compared to the unsuccessful ones)
Identifying patterns in the way people solve these problems can prove to be great design insights that go into the design of problem-solving solutions for those problems.
A lot of notation is the way it is because of history and inertia, rather than because practical considerations or requirements means it needs to be that way.
If there are changes we can make to make languages more approachable without making them worse in other ways, it makes sense to opt for making them more approachable.
Less than you may think. Leibniz and other mathematicians spent years debating notational forms in mathematics before settling on what we have. See Florian Cajori's _A History of Mathematical Notations_.
It's not their opinions. It's about how they naturally think.
And, yes, if I could change mathematical notation in a manner that made it easier to learn without introducing a more significant disadvantage, I would do it in a heartbeat.
Things are the way they are for a reason but that reason isn't necessarily that the way things are is the best.
It is a mistake and somewhat arrogant to view your domain experts as "5th graders".
Let me take the opportunity to plug a new language which I have spent the last 5 months designing: github.com/jbodeen/ava
An ava solution -- 9 lines of code, and 1 set of parentheses -- would look like this:
let rec sum list =
let are_we_at_the_end = 0 in
let take_a_number_and_the_rest_of_the_list n list =
add n ( sum list )
in
list
are_we_at_the_end
take_a_number_and_the_rest_of_the_list
in
Maybe we need to zoom out of ancient languages into more intuitive paradigms if programming is to become easier for more people to access -module(math).
-export([sum/1]).
sum(ListOfNumbers) ->
sum(ListOfNumbers, 0).
sum([Number | RestOfList], Subtotal) ->
sum(RestOfList, Subtotal + Number);
sum([], Total) ->
Total.
edit: blargh... sorry @simoncion, I didn't see your reply. It apparently takes me longer than 14min to type that out on my phone without typos + proper spaces to treat it like code :-)No worries. It's astonishing how absolutely awful on-screen phone keyboards still are for doing anything more involved than writing a brief human-language message.
Maybe. Compare your function to the equivalent Erlang one:
sum(L) ->
sum(L, 0).
sum([], Acc) ->
Acc;
sum([Num|Rest], Acc) ->
sum(Rest, Acc+Num).
Assuming that it's in a module called 'math', run it like so: math:sum([5,4,3,2,1]).
15sum = std::accumulate(begin, end, 0);
let listsum = foldl (+)
A study like this helps us gain inspiration and to remind ourselves how non-programmers think about programming problems.
In the words of the linked pdf: "Programming may be more difficult than necessary because it requires solutions to be expressed in ways that are not familiar or natural for beginners."
Law may be...
Physics may be...
Getting the point? Beginners may not always be the best yardstick of everything.
This study, and the person you're replying to, aren't saying that all programming languages are unnecessarily complicated and should be changed. They're just saying that they're inaccessible to beginners. The authors of the study note that they're designing a programming language for beginners, so these things are useful for them to know.
It occurs to me if you get it wrong, glass shards from the bottle could emerge before submerging into your flesh, so perform this trick at your own risk.
I do this anytime I don't have a wine opener handy.
Visual Basic also seems quite close, especially with features like Linq.
Honest question - what is there about Visual Basic that makes you say this? I've written small programs with it and on the surface it feels close to "C# if someone changed all the keywords".
Case insensitivity in string comparisons is a good example. It makes perfect sense to a non-programmer but is not at all what a programmer would expect.
"Non-programmer" isn't meant as a slight. This style of problem solving works great a significant portion of the time. Natural languages can describe a solution to a lot of problems very concisely because a) there's a lot of implicit context that clears up many of the potential ambiguities, and b) you're typically present and available to handle any unexpected situations that may arise. For many problems, the best solution is one that can be specified quickly, will work 90% of the time, and can be easily adjusted for most of the other 10% of the time. Natural languages and fuzzier thinking work great for this.
But this approach doesn't work well for problems where the solution is either too complex too be easily described using natural language, or situations where data sizes or time constraints make it unfeasible for you to be available to handle unexpected situations. In this case the solution requires all of the logic to be precise, unambiguous, and developed up front. It's a different way of thinking than what has typically been asked of humanity, and natural languages are pretty poor at expressing that logic.
I think the paper has some good points, but I'm not sure how much you can really draw from it other than verification that natural-style problem solving doesn't work well for the type of problems that are typically solved by programming. If you asked a bunch of experienced programmers to write programs that will tell you how to "go to the store and buy me some milk", you'd probably get similar results about how the programs didn't handle the many different unexpected situations that might occur in such a simple task.
For such solutions, let's say in the business domain - the programmer could work with the domain experts on the general structure of the domain model - business objects, members and methods - while the domain expert will design fill the methods, maybe validation rules(with some tool), all small code sections(so it might be easier to think un-ambigously) - and than the model will be fed to an automated system like naked-objects/ISIS that will handle all the technical stuff automatically.
Than if the system detects an ambiguity, it will offer debug info(and code view) in a format that domain experts understand, and let them fix it - or ask help. And of course you could add testing and code review with programmers and domain experts(who can now read the code) to the mix.
And yes, sure this won't fit every system. But it maybe extend the power of the domain expert.
>> or situations where data sizes or time constraints make it unfeasible for you to be available to handle unexpected situations.
For such situations, a search engine having access to the full code specified in an ambiguous language(not necessary natural), could help tools find/build an code containing an optimized form, and maybe offer help about how to integrate it.
The good thing is, both extremes are not mutually exclusive, but rather exist on a continuum. You can start with fuzzy specifications and progressively refine it by case-based reasoning and induction until you get some general, unambiguous rules. Programmers work this way when building new programs, even though they hate to admit it and like to say that the program logic emerges fully formed from the specifications (ha!), they just need to understand the problem in their heads first (no tinkering and trial-error happens in programming, right?).
I believe the next radically different family of languages will be one that embraces that fact and allows developers to better handle that progressive refinement in all steps of the process, rather than require the program to be fully formed and flawless in order to operate. In some sense, modern IDEs already work that way.
Prelude> sum [1, 2, 3] 6
Hey, you could even search for a library that sums lists for you in C, then include and call that function.
const auto & xs = {1, 2, 3};
cout << accumulate(begin(xs), end(xs), 0);A sum function is not very `function' at all. (It sure feels at home in functional languages, more than in imperative bit-by-bit piecemeal programming, sure.)
Also, why anthropomorphize the computer? And why are we "summarizing" instead of instructing the computer? The question asked for a declarative solution and then is surprised that the children gave declarative answers. [edit: I misread what was being said in that portion of the paper and that portion of has been replaced by this bit in square brackets]
The experiment seems extremely sloppy. It can't possibly show what it purports to show, there's way too much in the design of the study that could have biased the results, the sample sizes tiny, the task unclear, and the quantitative analysis subjective.
What list? Perhaps I'm just missing it or there's another link I haven't seen but they don't seem to mention having taught the kids anything--especially anything technical--before the Pac-Man study.
The paper points out that non-programmers (5th graders) have trouble with NOT, AND, and OR and suggest in a separate paper that table based queries can avoid some confusion with these Boolean operators. I'm sorry, but a programming language without Boolean operators is going to be worthless. Just because 5th graders haven't learned De Morgan's Laws doesn't mean that we should throw out Boolean operators. What about lambda expressions, functions as first class elements, higher dimensional arrays, recursion, complex numbers, binary and decimal internal integer representations, floating point with exponents, built in log functions, setjump/longjump, call-with-continuation, threads, concurrency, interrupt handlers, atomic locking, streams, files, relational data bases, the list goes on and on.
Programming in a programming language for Kids tends to be tedious and very concrete. Scratch bored me to tears. Perhaps its a good fit for kids, but it's not going to be used to write a web server. I just don't see how these "experiments" give us any insight into non-toy programming.
In the 1970's there were still plenty of professional programmers and fellow grad students that felt like programming in assembly language was the highest form of programming. It was challenging, I did my fair share, but it was also brutish and nasty. There were no powerful abstractions to facilitate ones programming. Everything was concrete and explicit and terrible. The history of programming languages has been to build a tower of increasingly powerful abstractions over the hardware below. C++ templates, Haskell's type system, Scheme's call-with-continuation, SQL, these are so far removed from the simple little operations being performed by the processor, but they give us the power to write the programs that we do.
The use of abstraction in programming isn't limited to programming languages. Libraries supporting matrix operations won't make sense to a 5th grader or anyone else that hasn't studied matrices. So how is a 5th grader going to describe rotation of a graphical element? They don't know matrix math or trigonometric functions? Should these be eliminated from programming languages? Operating systems also insulate us from the hardware through abstractions not present in the physical hardware: processes, scheduling, virtual memory, files, abstract sockets, networks, threads. What about the other tools we use like relational data bases, source code control systems like git, and bug trackers? How about pseudo-random numbers and encryption? What do 5th graders know of these?
Finally, some professional programmers have to understand deeper issues, programming complexity, turing incompleteness, regular expressions, context-free grammars, LR parsing, performance of algorithms, correctness arguments. All of these issues have some impact on programming. Are we really going to throw all of this out because it is confusing to 5th graders? or even adults that haven't studied these issues?
I do research into A.I., and often work with companies. I find problem fall into 3 categories. Approximately:
50% of problems are extremely trivial problems which we've know how to solve for at least 10 years, we just need to help the companies use the existing techniques.
15% of problems require techniques from the last 10 years or so, so require extensive up-to-date expertise but aren't interesting research.
5% of problems are interesting, hard problems which lead to interesting research problems.
30% of problems are so far beyond the state of the art they are impossible.
Helping people in that first 50% solve their problems without having to talk to us is an interesting area. At the moment they use tools like Excel and Microsoft Access. I believe there must be better tools for those problems, which aren't any more complicated. Why can't my mother easily produce (for a concrete example) create and update a schedule for her darts league, without needing me to help?
I also think the conclusion that people prefer sets over loops is biased because the problem domain is a database table where it is more natural to work with sets.
In any case i find the study interesting to compare with how people write software requirements and not to how languages are designed. Requirements are often written in natural language form and are often written by product managers that are non-programmers. I found the answers to be extremely similar to user stories seen in requirements, in particular the use of end user perspective when describing how pac man should move.
At this point in the development of programming languages, the problem is not really that we can't build languages that do what you want; by and large, for unambiguous specifications (and yes, that is a big qualifier), we can.
At this point, then, the conversation shifts from "how can I meet the machine's needs?" to "how can the machine meet my (programming) needs?" Another analogy: we're no longer just stone-age people looking for a rock that doesn't shatter when we hit things with it; we're can shape our rocks now, and we're trying to figure out what shape allows us to hit things hard without cutting our hands.
Go, functional and declarative programming! Oops, I gave it away. Sorry.
Obviously I can't extrapolate or make big assumptions about this tiny experiment but I underestimate my family members capabilities. Also, it is obvious that on complex areas of study it's very difficult to came up with a solution if you are a novice.
https://scholar.google.de/scholar?cites=9767640341703630929&...
A good search term is "computational thinking" which probably needs to be combined with a couple of synonyms for "non-programmer".
First, they take naive user reasoning as normative. Nobody remains a naive user for long. When I first started leaning to program, shifting from set-based to iteration-based reasoning about collections was a bit of a jolt, but it didn't take me long to become comfortable with it.
Second, they ignore that programming is an activity requiring much more precise reasoning than typical daily life. You must learn to think differently and it is beneficial for the notation to enforce this.
I will also point out that English-like programming languages have been promoted for decades and they haven't caught on.
Don't tell me what I need to do, tell me what You want to do. Mostly clients seem to think they need to come up with the way to accomplish stuff, rather than express the need and let the programmer figure out how to meet that need.