about summary refs log tree commit diff stats
path: root/042name.cc
Commit message (Collapse)AuthorAgeFilesLines
* 3309Kartik K. Agaram2016-09-091-6/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Rip out everything to fix one failing unit test (commit 3290; type abbreviations). This commit does several things at once that I couldn't come up with a clean way to unpack: A. It moves to a new representation for type trees without changing the actual definition of the `type_tree` struct. B. It adds unit tests for our type metadata precomputation, so that errors there show up early and in a simpler setting rather than dying when we try to load Mu code. C. It fixes a bug, guarding against infinite loops when precomputing metadata for recursive shape-shifting containers. To do this it uses a dumb way of comparing type_trees, comparing their string representations instead. That is likely incredibly inefficient. Perhaps due to C, this commit has made Mu incredibly slow. Running all tests for the core and the edit/ app now takes 6.5 minutes rather than 3.5 minutes. == more notes and details I've been struggling for the past week now to back out of a bad design decision, a premature optimization from the early days: storing atoms directly in the 'value' slot of a cons cell rather than creating a special 'atom' cons cell and storing it on the 'left' slot. In other words, if a cons cell looks like this: o / | \ left val right ..then the type_tree (a b c) used to look like this (before this commit): o | \ a o | \ b o | \ c null ..rather than like this 'classic' approach to s-expressions which never mixes val and right (which is what we now have): o / \ o o | / \ a o o | / \ b o null | c The old approach made several operations more complicated, most recently the act of replacing a (possibly atom/leaf) sub-tree with another. That was the final straw that got me to realize the contortions I was going through to save a few type_tree nodes (cons cells). Switching to the new approach was hard partly because I've been using the old approach for so long and type_tree manipulations had pervaded everything. Another issue I ran into was the realization that my layers were not cleanly separated. Key parts of early layers (precomputing type metadata) existed purely for far later ones (shape-shifting types). Layers I got repeatedly stuck at: 1. the transform for precomputing type sizes (layer 30) 2. type-checks on merge instructions (layer 31) 3. the transform for precomputing address offsets in types (layer 36) 4. replace operations in supporting shape-shifting recipes (layer 55) After much thrashing I finally noticed that it wasn't the entirety of these layers that was giving me trouble, but just the type metadata precomputation, which had bugs that weren't manifesting until 30 layers later. Or, worse, when loading .mu files before any tests had had a chance to run. A common failure mode was running into types at run time that I hadn't precomputed metadata for at transform time. Digging into these bugs got me to realize that what I had before wasn't really very good, but a half-assed heuristic approach that did a whole lot of extra work precomputing metadata for utterly meaningless types like `((address number) 3)` which just happened to be part of a larger type like `(array (address number) 3)`. So, I redid it all. I switched the representation of types (because the old representation made unit tests difficult to retrofit) and added unit tests to the metadata precomputation. I also made layer 30 only do the minimal metadata precomputation it needs for the concepts introduced until then. In the process, I also made the precomputation more correct than before, and added hooks in the right place so that I could augment the logic when I introduced shape-shifting containers. == lessons learned There's several levels of hygiene when it comes to layers: 1. Every layer introduces precisely what it needs and in the simplest way possible. If I was building an app until just that layer, nothing would seem over-engineered. 2. Some layers are fore-shadowing features in future layers. Sometimes this is ok. For example, layer 10 foreshadows containers and arrays and so on without actually supporting them. That is a net win because it lets me lay out the core of Mu's data structures out in one place. But if the fore-shadowing gets too complex things get nasty. Not least because it can be hard to write unit tests for features before you provide the plumbing to visualize and manipulate them. 3. A layer is introducing features that are tested only in later layers. 4. A layer is introducing features with tests that are invalidated in later layers. (This I knew from early on to be an obviously horrendous idea.) Summary: avoid Level 2 (foreshadowing layers) as much as possible. Tolerate it indefinitely for small things where the code stays simple over time, but become strict again when things start to get more complex. Level 3 is mostly a net lose, but sometimes it can be expedient (a real case of the usually grossly over-applied term "technical debt"), and it's better than the conventional baseline of no layers and no scenarios. Just clean it up as soon as possible. Definitely avoid layer 4 at any time. == minor lessons Avoid unit tests for trivial things, write scenarios in context as much as possible. But within those margins unit tests are fine. Just introduce them before any scenarios (commit 3297). Reorganizing layers can be easy. Just merge layers for starters! Punt on resplitting them in some new way until you've gotten them to work. This is the wisdom of Refactoring: small steps. What made it hard was not wanting to merge *everything* between layer 30 and 55. The eventual insight was realizing I just need to move those two full-strength transforms and nothing else.
* 3248Kartik K. Agaram2016-08-251-1/+2
|
* 3247Kartik K. Agaram2016-08-251-22/+24
|
* 3120Kartik K. Agaram2016-07-211-3/+3
| | | | | | | | Always show instruction before any transforms in error messages. This is likely going to make some errors unclear because they *need* to show the original instruction. But if we don't have tests for those situations did they ever really work?
* 3096Kartik K. Agaram2016-07-031-0/+1
|
* 3022Kartik K. Agaram2016-05-271-12/+3
| | | | Clean up 3020.
* 3020 - names in chessboard testsKartik K. Agaram2016-05-261-0/+12
| | | | | | | | Extremely ugly change. Also ended up fixing some places where I was mixing up sources and sinks. But I'm not going to bother updating edit/ and sandbox/ apps. Just too many scenarios to clean up.
* 2990Kartik K. Agaram2016-05-201-6/+6
| | | | | | | | | | Standardize quotes around reagents in error messages. I'm still sure there's issues. For example, the messages when type-checking 'copy'. I'm not putting quotes around them because in layer 60 I end up creating dilated reagents, and then it's a bit much to have quotes and (two kinds of) brackets. But I'm sure I'm doing that somewhere..
* 2955 - back to more refcount housekeepingKartik K. Agaram2016-05-121-1/+1
| | | | | Update refcounts of address elements when copying containers. Still lots to do; see todo list at end of 036refcount.cc.
* 2898 - start filling in missing refcountsKartik K. Agaram2016-05-031-1/+1
| | | | | | | This commit covers instructions 'put', 'put-index' and 'maybe-convert'. Next up are the harder ones: 'copy' and 'merge'. In these cases there's a non-scalar being copied, and we need to figure out which locations within it need to update their refcount.
* 2891 - precompute container sizes and offsetsKartik K. Agaram2016-05-021-1/+1
| | | | | | | It's a bit of a trade-off because we need to store copies of container metadata in each reagent (to support shape-shifting containers), and metadata is not lightweight and will get heavier. But it'll become more unambiguously useful when we switch to a compiler.
* 2864 - replace all address:shared with just addressKartik K. Agaram2016-04-241-2/+1
| | | | | | | Now that we no longer have non-shared addresses, we can just always track refcounts for all addresses. Phew!
* 2861 - 'maybe-convert' no longer returns addressKartik K. Agaram2016-04-231-2/+4
|
* 2859 - rename 'get-address' to 'get-location'Kartik K. Agaram2016-04-231-2/+3
| | | | | | This reinfoces that it's only really intended to be used by 'wait-for-location'. To reinforce that we also move it to the same layer as 'wait-for-location'.
* 2831 - bugfix in static arraysKartik K. Agaram2016-04-131-0/+18
| | | | | | | | | | | I'd started using size_of() in transforms at some point, but not gotten around to actually updating it to support arrays before run-time. Wish there was a way I could statically enforce that something is only called at transform time vs runtime. Thanks Ella and Caleb Couch for finding this issue. Static arrays are likely still half-baked, but should get a thorough working-over in coming weeks.
* 2830 - bring back deleted test from 2829Kartik K. Agaram2016-04-101-6/+7
| | | | Issue 1 in 2829 is now fixed.
* 2829 - issues while switching to 'put'Kartik K. Agaram2016-04-101-5/+5
| | | | | | | | | | | | | | | | 1. It turns out we couldn't overload 'get' and 'get-address' until now, because transform_names looks for those names, and the resolve_ambiguous_calls transform happens before transform_names. Why does resolve_ambiguous_calls happen before transform_names? Because if my students made mistakes in the ingredients to an instruction they got overzealous errors from resolve_ambiguous_calls. Now this impacts 'put' as well, which is already overloaded for tables. Not sure what to do about this; I'm going to go back to the overzealous errors, and just teach students to visually scan past them for now. 2. I need addresses in a third place besides storing to containers and arrays, and managing the heap -- to synchronize routines. wait-for-location requires an address. Not sure what to do about this..
* 2804 - support stashing arraysKartik K. Agaram2016-03-211-4/+7
| | | | | Now to extend 'stash' for arrays, just extend array-to-text-line instead and perform the lookup inside it.
* 2803Kartik K. Agaram2016-03-211-3/+3
| | | | | Show more thorough information about instructions in the trace, but keep the original form in error messages.
* 2799 - new approach to undoing changes in testsKartik K. Agaram2016-03-201-4/+9
| | | | | | | | As outlined at the end of 2797. This worked out surprisingly well. Now the snapshotting code touches fewer layers, and it's much better behaved, with less need for special-case logic, particularly inside run_interactive(). 30% slower, but should hopefully not cause any more bugs.
* 2773 - switch to 'int'Kartik K. Agaram2016-03-131-12/+12
| | | | This should eradicate the issue of 2771.
* 2735 - define recipes using 'def'Kartik K. Agaram2016-03-081-11/+11
| | | | | | | | | | | | I'm dropping all mention of 'recipe' terminology from the Readme. That way I hope to avoid further bike-shedding discussions while I very slowly decide on the right terminology with my students. I could be smarter in my error messages and use 'recipe' when code uses it and 'function' otherwise. But what about other words like ingredient? It would all add complexity that I'm not yet sure is worthwhile. But I do want separate experiences for veteran programmers reading about Mu on github and for people learning programming using Mu.
* 2718 - stop crashing on unknown spaceKartik K. Agaram2016-02-261-2/+16
| | | | | I'm going to stop wasting precious first-line characters on 'bugfix:'. It's going to be all bugfixes for a while I think.
* 2712Kartik K. Agaram2016-02-261-8/+8
|
* 2709Kartik K. Agaram2016-02-251-2/+0
| | | | | Only Hide_errors when strictly necessary. In other places let test failures directly show the unexpected error.
* 2685Kartik K. Agaram2016-02-191-3/+3
| | | | | | | | | | | | | | | | Stack of plans for cleaning up replace_type_ingredients() and a couple of other things, from main problem to subproblems: include type names in the type_tree rather than in the separate properties vector make type_tree and string_tree real cons cells, with separate leaf nodes redo the vocabulary for dumping various objects: do we really need to_string and debug_string? can we have a version with *all* information? can we have to_string not call debug_string? This commit nibbles at the edges of the final task, switching from member method syntax to global function like almost everything else. I'm mostly using methods just for STL in this project.
* 2667 - redo container data structureKartik K. Agaram2016-02-171-3/+2
| | | | I've been gradually Greenspunning reagents. Just go all the way.
* 2633Kartik K. Agaram2016-02-061-4/+0
|
* 2614Kartik K. Agaram2016-01-291-5/+5
|
* 2576 - distinguish allocated addresses from othersKartik K. Agaram2016-01-191-1/+3
| | | | | | | | | | | | | | | | This is the one major refinement on the C programming model I'm planning to introduce in mu. Instead of Rust's menagerie of pointer types and static checking, I want to introduce just one new type, and use it to perform ref-counting at runtime. So far all we're doing is updating new's interface. The actual ref-counting implementation is next. One implication: I might sometimes need duplicate implementations for a recipe with allocated vs vanilla addresses of the same type. So far it seems I can get away with just always passing in allocated addresses; the situations when you want to pass an unallocated address to a recipe should be few and far between.
* 2562Kartik K. Agaram2016-01-171-3/+5
| | | | | | | | | | | | We want to use the type 'recipe' for recipe *variables*, because it seems nicer to say `recipe number -> number` rather than recipe-ordinal, etc. To support this we'll allow recipe names to be mentioned without any type. This might make a couple of places in this commit more brittle. I'm dropping error messages, causing them to not happen in some situations. Maybe I should just bite the bullet and require an explicit :recipe-literal. We'll see.
* 2555Kartik K. Agaram2016-01-111-2/+2
|
* 2546 - another phase-ordering constraintKartik K. Agaram2015-12-191-1/+1
| | | | Thanks Caleb Couch.
* 2622Kartik K. Agaram2015-12-131-3/+3
|
* 2504 - support to-text in 'stash'Kartik K. Agaram2015-11-281-8/+9
|
* 2494Kartik K. Agaram2015-11-281-1/+1
| | | | | Some more structure to transforms, and flattening of dependencies between them.
* 2473 - bad idea to use /raw with multiple intentionsKartik K. Agaram2015-11-221-2/+2
| | | | | /raw is to express absolute addresses /unsafe is to sidestep type-checking in test setup
* 2456Kartik K. Agaram2015-11-171-4/+8
|
* 2401Kartik K. Agaram2015-11-081-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I tried to not populate the type at an early stage, and to pull out the type computations for all reagents into a separate transform grouped with but before the other type deduction transforms. But it seemed less readable to not mention types at all in layer 10. So we'll stick with our current approach, but try to be disciplined about grouping all the type transforms together, so that we can reason about whether a pass belongs before or after type deduction. (Doesn't seem rigorous enough for the name 'type inference'.) In particular, static dispatch and specialization of generics (resolve_ambiguous_calls) needs to happen after all type inference has completed, so that the only missing types are the generic type ingredients. In general I've been living in constant fear of the phase-ordering problem. No matter how many tests I write, I can't be sure that there isn't some corner case where my phases will be proven to be in a sub-optimal ordering. When I build the mu compiler in mu I'll want to also use the ability to perform static analyses in mu programs using mu userland capabilities. That would allow me to be sure that no phase writes to some field of reagent after some other purely checking phase reads it. Then all you have to do is be disciplined about not doing checking in mutating phases (which we currently aren't; hello check_or_set_invalid_types). Hmm, but I think this line of thought gives me some confidence now that I'm ok so far. The only field of reagents being modified after parsing/initialization is the type. So all I care about is whether each transform happens before or after all types are available. If I later start writing other fields or properties then I'll need to perform similar analysis for them, and it might get complicated enough to need a state diagram where partially filled out properties inhabit separate states from completely inferred properties.
* 2383 - new concern: idempotence of transformsKartik K. Agaram2015-11-061-1/+1
| | | | | I'd not paid any attention to it so far, but I need to do so from now on.
* 2382Kartik K. Agaram2015-11-061-0/+1
| | | | Starting to leave commented out prints again out of desperation.
* 2379 - further improvements to map operationsKartik K. Agaram2015-11-061-1/+1
| | | | | | | Commands run: $ sed -i 's/\([^. (]*\)\.find(\([^)]*\)) != [^.]*\.end()/contains_key(\1, \2)/g' 0[^0]*cc $ sed -i 's/\([^. (]*\)\.find(\([^)]*\)) == [^.]*\.end()/!contains_key(\1, \2)/g' 0[^0]*cc
* 2377 - stop using operator[] in mapKartik K. Agaram2015-11-061-21/+21
| | | | | | | | | | | | | | | | I'm still seeing all sorts of failures in turning on layer 11 of edit/, so I'm backing away and nailing down every culprit I run into. First up: stop accidentally inserting empty objects into maps during lookups. Commands run: $ sed -i 's/\(Recipe_ordinal\|Recipe\|Type_ordinal\|Type\|Memory\)\[\([^]]*\)\] = \(.*\);/put(\1, \2, \3);/' 0[1-9]* $ vi 075scenario_console.cc # manually fix up Memory[Memory[CONSOLE]] $ sed -i 's/\(Memory\)\[\([^]]*\)\]/get_or_insert(\1, \2)/' 0[1-9]* $ sed -i 's/\(Recipe_ordinal\|Type_ordinal\)\[\([^]]*\)\]/get(\1, \2)/' 0[1-9]* $ sed -i 's/\(Recipe\|Type\)\[\([^]]*\)\]/get(\1, \2)/' 0[1-9]* Now mu dies pretty quickly because of all the places I try to lookup a missing value.
* 2358 - starting to tackle the phase ordering problemKartik K. Agaram2015-11-041-2/+2
| | | | | | | A new externality is starting to make its presence felt. Until I sort this out it's going to be hard to finish making duplex-list generic.
* 2321 - more preparations for static dispatchKartik K. Agaram2015-10-291-4/+3
| | | | | Deduce operation id from name during transform rather than load, so that earlier transforms have a chance to modify the name.
* 2311Kartik K. Agaram2015-10-291-6/+7
|
* 2277 - reagents now have a tree of typesKartik K. Agaram2015-10-251-6/+7
|
* 2270Kartik K. Agaram2015-10-121-1/+1
| | | | Thanks Caleb Couch.
* 2258 - separate warnings from errorsKartik K. Agaram2015-10-061-27/+28
| | | | | | | At the lowest level I'm reluctantly starting to see the need for errors that stop the program in its tracks. Only way to avoid memory corruption and security issues. But beyond that core I still want to be as lenient as possible at higher levels of abstraction.
* 2226 - standardize warning formatKartik K. Agaram2015-10-011-22/+22
| | | | | | | | Always show recipe name where error occurred. But don't show internal 'interactive' name for sandboxes, that's just confusing. What started out as warnings are now ossifying into errors that halt all execution. Is this how things went with C and Unix as well?