1. 3

    Collapsing Towers of Interpreters, the work of GraalVM/Truffle and PyPy.

    Exciting times! CToI deserves its own lobsters post.

    1. 2

      Submit it next week then.

    1. 1

      Please use only uBlock Origin

       ____  ____    _              ____  _            _    
      |  _ \/ ___|  / \   _   _   _| __ )| | ___   ___| | __
      | |_) \___ \ / _ \ (_) | | | |  _ \| |/ _ \ / __| |/ /
      |  __/ ___) / ___ \ _  | |_| | |_) | | (_) | (__|   < 
      |_|   |____/_/   \_(_)  \__,_|____/|_|\___/ \___|_|\_\
                                                            
        ___       _       _       
       / _ \ _ __(_) __ _(_)_ __  
      | | | | '__| |/ _` | | '_ \ 
      | |_| | |  | | (_| | | | | |
       \___/|_|  |_|\__, |_|_| |_|
                    |___/         
      

      https://github.com/gorhill/uBlock

        1. 1

          …and csvkit.

        1. 4

          Maybe our idea of the “web” is what’s too small! Web Assembly is more than appropriately named in my opinion for how well it works for the transfer and immediate evaluation of procedures over networks, but the imagination of many for the idea of the web is lost beyond the horizon of their web browser. There’s a lot of our thinking that could use a bit of Imagination Fuel

          1. 2

            I’m very much on that team. I’m giving a full conference talk about it in Barcelona next week. Different framing work well for different people, so I picked this one for this post, as I wanted it to be short, and this framing is shorter.

            1. 1

              Didn’t mean it to be nitpicking, it’s too easy to accidentally write posts in that style lol. Very good article and I’m excited for any future ones about this topic!

              1. 1

                Oh! I’m from Barcelona, which conference are you attending? I may try to attend.

                1. 1

                  Friday: https://jscamp.tech/schedule/

                  It says TBD but it’s a wasm talk.

                  1. 1

                    Damn! tickets are sold out :( Will the talk be uploaded afterwards?

                    1. 1

                      I believe so! I’d like it to be; the last time I gave this talk it wasn’t recorded.

              2. 2

                Yeah I think we browsers have become too big, monolithic, and homogeneous. I would like to see more diversity in web clients. Those clients could use WebAssembly outside the context of the browser.

                The browser has a very specific and brittle set of security policies, and WebAssembly doesn’t change that. It will inherit the same problems that JavaScript has.

                1. 3

                  Sort of! You know, at parse time, every function a wasm program could call. This is extremely useful in a security context.

                2. 2

                  Imagination Fuel

                  Love It. The captures a lot of meetings I have been trying to have with folks at work. They are thinking low level performance fixes for things, while necessary, they are having a huge problem jumping up a couple abstraction levels and thinking transformatively.

                1. 2

                  If the concern is leaks, defense contractors like Galois might be able to get DARPA to change that policy. My idea would be a split between stuff that will definitely be FOSS and stuff that might be sensitive. Like Compartmented Mode Workstations or with Qubes, they could even isolate them in VM’s whose border color, labels, and firewall policies reflect the difference. The sensitive one would be used in a new, custom project or derivative that pulls in the open one. Whereas, the security policy wouldn’t led sensitive stuff interact with the Internet at all.

                  Quite a few products on the market for this on top of free stuff like Qubes or Muen. One can also use multiple boxes with KVM switch if worried about breaks. Anyone with DARPA or Defense experience think this proposal has a good chance of working?

                  1. 3

                    I think there’s often a fair amount of misinformation regarding the creation of OSS by government contractors.

                    Yes, contractors like Galois have to play by the rules the government sets for them, including classification. The concern of “leaks” is there, but it’s subtle: tight coupling of components that probably should be open sourced with other components that probably should be classified.

                    So there’s a tendency to “overclassify” and lump everything together. However, companies can still make a case for why things should be open sourced - after all, they worked on it, and if the development was separate enough, it won’t be “polluted.”

                    Galois has a history of trying to push things into the open source domain, and their reputation precedes them enough that they would probably not classify a C to Rust translator.

                    As for your idea, they’d much prefer to just use two separate computers.

                    1. 5

                      As for your idea, they’d much prefer to just use two separate computers.

                      As much as I love OSS, I would do the same thing. The risk is that person that works on both classified and non-classified projects could make a mistake an do a git push containing classified info. The solutions to problems problems is better structure, not being more careful.

                      1. 1

                        The CMW’s I mentioned specifically try to prevent that with labelled data and interfaces. You can’t mix them without a manual approval, reclassification, etc. One could do the same kind of thing with VM’s where a transfer required internal, human review.

                  1. 2

                    The whole thing is great, but one idea that seems particularly useful in arbitrary languages without regard to how it fits with other features is to specify the list of globals used by a function. In Python-like syntax, imagine this:

                    def draw_quad(origin, left, up) [m]:
                        m.Position3fv(origin - left - up)
                        m.Position3fv(origin + left - up)
                        m.Position3fv(origin + left + up)
                        m.Position3fv(origin - left + up)
                    

                    Now you get a guarantee that the function uses zero globals besides m.

                    1. 4

                      In PHP you have something like that, global variables are not accesible from inside functions unless you specifically allow each one you want

                      $m = new M();
                      function draw_quad($orgin, $left, $up){
                          global $m; // or $m = $_GLOBALS['m'];
                          $m->Position3fv($origin - $left -$up);
                          $m->Position3fv($origin + $left - $up);
                          $m->Position3fv($origin + $left + $up);
                          $m->Position3fv($origin - $left + $up);
                      

                      in practice, I haven’t found useful global variables other then the contextual ones ($_POST. $_GET, $_SESSION), which are superglobal and always defined

                      1. 2

                        I’d like to see something similar but generalised to “contextual” environmental bindings, rather than traditional global vars. And a compiler that ensures that somewhere in all call chains the binding exists. But you might want a global in some cases, or a “threadlocal”, or an “import” of some sort, or something like the context in react, etc.

                        Some mechanism in which the compiler makes sure the environmental dependencies are fulfilled, without necessarily requiring that value be propagated explicitly through each owner/container between provider and consumer.

                        1. 4

                          I can’t find it but Scala has an extra context var that is passed with function invocation.

                          And early Lisps had dynamic scope, meaning that a var bound to the next occurrence up the call stack.

                          Both of these mechanisms supply the building blocks for AoP, so that a programmer can mixin orthogonal properties.

                          1. 3

                            And early Lisps had dynamic scope, meaning that a var bound to the next occurrence up the call stack.

                            Today they still have it - see DEFVAR and DEFPARAMETER in Common Lisp.

                            1. 2

                              I can’t find it but Scala has an extra context var that is passed with function invocation.

                              In Scala you can use implicit parameters for this:

                              def foo(origin: Vec3, left: Vec3, up: Vec3)(implicit m: Context) {
                                  m.Position3fv(origin - left - up)
                                  m.Position3fv(origin + left - up)
                                  m.Position3fv(origin + left + up)
                                  m.Position3fv(origin - left + up)
                              }
                              

                              In Haskell you could use a reader/writer/state monad thingy. In Koka or Eff you could use effects.

                              1. 2

                                Yeah, Scala’s context is probably closest to what I’m thinking of, from what I know of it.

                              2. 4

                                You can kinda get this with effect types. Effect types let you label certain functions as using resource A or B, and then you can have a documentation mechanism for what dependencies are used, without passing stuff around.

                                It can still get a bit heavy (at least it is in Purescript), but less so than dependency injection

                              3. 1

                                A compiler or analyzer should be able to tell you that just from what variables or expressions go into the function. A previously-declared global would be one of the arguments. Why do we need to declare it again in the function definition?

                                1. 1

                                  See my final sentence. “Now you get a guarantee that the function uses zero globals besides m.” The program documents/communicates what it uses. The compiler ensures the documentation is always up to date.

                                  In my example, m is not one of the arguments. Because m is a global, lexically accessible anyway in the body of the function. There’s no redundancy here.

                                  1. 0

                                    I’m saying a compiler pass should be able to do the same thing without a language feature. I think it won’t be important to that many people. So, it will probably be optional. If optional, better as a compiler pass or static analysis than a language feature. It might also be an easy analysis.

                                    1. 3

                                      You’re missing the point. It’s a list of variables that the code can access anyway. What would a compiler gain by analyzing what globals the function accesses?

                                      There are many language features that help the compiler do its job. This isn’t one of them. The whole point is documentation.

                                      (Yes, you could support disabling the feature, using say syntax like [*]. C++ has this. Just bear in mind that compilers also don’t require code comments, and yet comments are often a good idea. SImilarly, even languages with type inference encourage documenting types in function headers.)

                                2. 1

                                  What if the Position3fv method uses global variable n? You also need to specify that for draw_quad. This quickly blows up like checked exceptions in Java and people want shortcuts.

                                  1. 2

                                    The problem with checked exceptions is that they discourage people from using exceptions. But there’s no problem in discouraging people from using global variables.

                                    I don’t mean to imply that I want all code to state what it needs all the time. In general I’m a pretty liberal programmer. It just seems like a good idea to give people the option to create “checkable documentation” about what globals a piece of code requires.

                                1. 6

                                  The fact that Guix is written in Scheme is a big appeal for me as opposed to Nix’s custom language. I preferred Nix as a way to support a standard environment (it has more packages), but this new feature makes the distribution of fat binaries a lot simpler than the other solutions. Less is more!

                                  1. 1

                                    FWIW, I tried to dissuade Gentoo from using Bash and Nix from creating their own language, both at basically around the 0.0.1 timeframe. I guess I am not terribly persuasive. Guix and Nix should merge. The separation is kinda ridiculous.

                                    1. 3

                                      Guix and Nix should merge.

                                      Seems like a great idea until you consider Guix’s commitment to freedom, and as a result blobless experience. Unless NixOS adopted that stance as well, the philosophical incompatibility would doom it. Nix adopting guile is more likely, I’d say, especially since guile did have a lua like front end that might make it a bit easier to slowly migrate everything…

                                      1. 2

                                        It is similar to vegetarian and non-vegetarian, one can have a blobless, freedom filled diet and then occasionally should they choose, sprinkle some bin01bits on top.

                                        1. 1

                                          I upvoted, but as a vegan, I kind of take offense to vegetarians (in a half hearted way, of course), who only “half” commit. But, I recognize that not everyone does it for the animals (even vegans).

                                          But, why would you go out of your way to run a completely free system, only to sprinkle some blobbits on it? That completely invalidates the point! That blob, is where the nasty things that disrespect your freedoms are.

                                          1. 1

                                            you wouldn’t run it for the freeness, but supposedly guix has some other strengths as well

                                        2. 1

                                          I didn’t realize Guix forbade blobs (though I’m not surprised, given its origin). Is there a with-blob version of Guix? I didn’t see one, but that doesn’t necessarily mean no…

                                          1. 1

                                            Obviously, you can acquire and install the blobs yourself, and I’m sure there are blog posts around in support of that. But, yeah, it’s like Trisquel, gNewsense, and the others that have similar governance for totally-libre.

                                            1. 1

                                              I haven’t used it in a long time, but I thought that you could point Guix at the package store from Nix, similar to how you can point Debian at apt repos from other sources. You would have to be really careful with this; I remember early on getting burned because I asked Nix to install Firefox and it gave me Firefox-with-adobe-flash which was pretty gross.

                                          2. 3

                                            Ha! Well, there must be an alternate universe where you managed to convince them ;) I think they do borrow some ideas and even some code (I remember a FOSDEM talk from Ludovic last year mentioning that). Implementation wise, I would suspect Guix has the upper hand, but the restriction to GNU packages is problematic not you need specific packages.

                                        1. -1

                                          Funny, this has a name, Point Free Style

                                          1. 4

                                            This is not really the same thing. Here we’re talking about folks extracting local variables into methods unnecessarily.

                                            1. 1

                                              Pointless Free Style

                                          1. 4

                                            I have been working on a blog post about this topic. The compiler in Warren’s “Logic programming and compiler writing” is about 200 lines IIRC. I think it could be interesting to do more in this vein.

                                            1. 4

                                              EDIT: Oops, I think you misunderstood the challenge like a lot of other people in this thread. It’s not about a compiler that’s 100 lines. It’s about reading a 100 line function that shows the structure of an 8,000 line (or 80K line, or 800K line) compiler.

                                              If you click through to the post I think that’s clear, although I can understand why the title was confusing.

                                              You can barely write a tokenizer for Python, JavaScript, or C in 100 lines. The “production” tokenizers are 500-2000 lines by themselves.

                                              100-line compilers are interesting from a pedagogical standpoint, but they don’t pass the test of “Somebody who doesn’t care about compilers built something useful with this.”


                                              OK awesome, I’m looking forward to it! I wanted to do a blog post about it too, but I likely won’t have time before my trip this summer [1]. To do a good job I would want to look at more existing compilers. I want to hear someone else’s take and see more examples.

                                              Part of the theme of my blog is “theory vs practice”, and in theory everyone thinks of their compiler as a series of transformations, and that’s how you draw it on the blackboard.

                                              But in practice, you rarely see the source code reflect this!

                                              The structure that this compiler had was almost unbelievable until I refactored it. Multiple inheritance was used instead of if statements!!! There were objects that you had to call methods on in a certain order, with hidden state, rather than the state being explicit on the stack.

                                              [1] http://www.oilshell.org/blog/2018/03/25.html

                                              1. 2

                                                ? I am confused. Are you talking about a 100 line top level function of a compiler ? So you are looking for a sufficiently compact yet expressive piece of compiler poetry.

                                                1. 2

                                                  100-line compilers are interesting from a pedagogical standpoint, but they don’t pass the test of “Somebody who doesn’t care about compilers built something useful with this.”

                                                  Fennel’s compiler is exactly 100 lines, and I’d argue it’s genuinely useful: https://github.com/bakpakin/Fennel/blob/master/fennel.lua#L600

                                                  It doesn’t do as much as most compilers, but that’s kind of the point. It does exactly one thing (bring a new more flexible syntax to an existing runtime without any new semantics) but it does it very well.

                                                  1. 1

                                                    A lot of people are interpreting this question as 100 lines TOTAL, which is what I was referring to. Fennel apears to be more than that.

                                                    But this structure is not what I’m looking for. I’m looking for the stages of the compiler all in one function – see my example. This compile1() function looks like a single stage that takes the AST as input.

                                                    1. 1

                                                      This compile1() function looks like a single stage that takes the AST as input.

                                                      In a lisp, the reader is exposed as its own independent first-class feature and isn’t considered part of the compiler. Many lisps have another representation between what the reader returns and the fully-annotated AST used by the compiler, but Fennel doesn’t.

                                              1. 3

                                                IPV6

                                                    2606:4700:4700::1111
                                                    2606:4700:4700::1001
                                                
                                                1. 1

                                                  Just a note if anyone finds this later, I’ve been unable to find PDFs for the books listed. The books themselves are excellent, and well worth ones time if you’re interested in that sort of thing.

                                                  1. 1

                                                    Correct, the books are .tgz of html, but they are still self contained, downloadable books.

                                                    lf.tgz
                                                    plf.tgz
                                                    vfa.tgz
                                                    
                                                    1. 1

                                                      Absolutely, I just got excited, thought I’d be able to print them out after all. Thanks for posting the link.

                                                    1. 2

                                                      Two (free) books on beginning category theory mentioned in the question and answer period

                                                      1. 2

                                                        This is an ideal problem for Prolog.

                                                        1. 5

                                                          Running your browser as a different user is an interesting challenge. Under normal circumstances I want to save my bank statement PDFs in my home directory. I want to upload my burrito pictures to Twitter. Slicing this off to a separate user is a significant usability setback.

                                                          1. 2

                                                            It does seem like a silly way to approximate better ideas in privilege separation.

                                                            1. 2

                                                              Better ideas like those already implemented in Chrome, which usually uses all means of sandboxing a platform can provide? (including the sec comp sys call filtering on Linux)

                                                              1. 1

                                                                Running as a non-unique unprivileged user means that user can potentially access much more than was intended. If nobody is running both your web and database servers. A compromise in either is a compromise in both.

                                                                1. 1

                                                                  I think my issue with the OP is more the underlying semantics of the Unix model. A “user” is too heavyweight and coarse an abstraction for handling privilege separation, and carries along with it too much historical baggage. But nobody is doing capabilities, which are IMO the correct mechanism. One muddles along, I suppose.

                                                                  1. 1

                                                                    Creating a unique UID for an operation could be a very clean separation of privs. How is a different UID to heavy weight? The coarseness is point, it is an unequivocal separation between the main account and the account of the untrusted process.

                                                                    Mount a FUSE interposer in the sandbox and all kinds of FS behaviors could be proxied through.

                                                                    1. 1

                                                                      Unix users carry a lot of implicit assumptions about privilege with them. Have you ever tried to do complex access control with UID/GID permissions? It’s a nightmare.

                                                                      In a world where the default model of computation involves a large number of actual humans proxied through Unix users logging into an 11/750 or a Sparcstation 20, maybe the Unix user model holds. In a world where 99.9999% of computers are single-user at all times, it’s way too heavy and ill-fitting an abstraction.

                                                            1. 2

                                                              Anyone able to speak to pony versus erlang/otp?

                                                              1. 16

                                                                Erlang. Rock solid. Mature as hell. Pony. New Kid on the Block. Immature as hell.

                                                                Pony draws a lot of inspiration from Erlang and has drawn interest from Erlang fans. Pony has a lot better performance than Erlang. It’s designed for correctness and speed.

                                                                Erlang has OTP and has taken care of a ton issues over the years. Pony has a very small standard lib, its saving grace on the library front is excellent C FFI.

                                                                Pony has a great type system that helps you write safe concurrent code. People like to compare it to Rust at times because of that.

                                                                Erlang has both concurrent and distributed version. Pony only has concurrent at the moment although plans are in the works for distributed Pony.

                                                                Tons of people are running Erlang in production. Pony not so much.

                                                                If you have particular questions, I’d suggest dropping by #ponylang on Freenode or checking out the mailing list.

                                                                1. 2

                                                                  Could you compare Pony vs Alice ?

                                                                  1. 4

                                                                    I like Alice ML. I maintain a github repository to keep Alice ML building. Pony is entirely asynchronous. There are no blocking operations. Some features of Alice ML that Pony doesn’t have or is different from:

                                                                    • Blocking operations - via futures and promises. So spawning an operation in a thread in Alice ML returns a future containing the value returned by the operation. If the operation has not yet finished in the thread then any other thread attempting to use that value will block until it is available. Code tends to look quite imperative and easy to follow. There’s no need to break up async operations into requests and replies or use callbacks.
                                                                    • Constraint programming built in.
                                                                    • Optional lazy evaluation.
                                                                    • The ability to serialize and deserialize language constructs. You can serialize entire modules, containing functions, and deserialize them on other machines and architectures. The component system of Alice is based on this.
                                                                    • Distributed functionality.

                                                                    Some things that Alice lacks compared to Pony:

                                                                    • Pony compiles to native code via LLVM. Alice uses a bytecode interpreter with a JIT based on GNU Lightning.
                                                                    • Pony’s garbage collection system is more advanced with per actor heaps and the ability to GC actors that cannot receive messages anymore. Alice uses a simple stop the world mark and sweep IIRC.
                                                                    • Pony has an easy to use FFI allowing calling C code and having C code call Pony code with in-language declarations. Alice requires interacting with the Seam VM in C++ and implementing wrappers. These are compiled to shared libraries that can then be loaded from Alice.
                                                                    • Pony is multicore - actor behaviours are run on available cores and uses a work stealing scheduler (I believe). Alice is single threaded with multiple green threads run within a scheduler in that single thread. The Seam VM is not multicore.
                                                                    • Pony has the capability system and the ability to have compile time prevention of deadlocks. You can see some examples on the Alice ML mailing list of implementations of channels and other things where subtle data races and deadlocks occur if they are not well thought out - even when using Alice ML features.

                                                                    I would really like to see an Alice ML VM written in Pony that uses Pony to take advantage of it’s efficient runtime. That would make for an interesting project.

                                                                    1. 1

                                                                      I’m not familiar with Alice

                                                                      1. 2

                                                                        Pony looks amazing. Do you think a transpiler from Erlang to Pony would be possible? Implement the Erlang runtime in Pony?

                                                                        1. 6

                                                                          This is a really interesting question! (Full disclosure: I’m the Pony language designer, so I have a bias).

                                                                          Erlang uses immutable data types, and Pony can express those. Erlang has actors, and Pony can express those. Erlang is dynamically typed, but Pony is statically typed. However, using Hindley-Milner unification, it would be possible to generate Pony interfaces (i.e. structural types) that expressed the implicit dynamic typing constraints in an Erlang program. So far, so good.

                                                                          However, there’s a core semantic difference, which is that Erlang allows a blocking receive that pattern matches on the queue. In contrast, in Pony, all actor behaviours are strictly asynchronous. This would make an Erlang to Pony transcoder tricky - not impossible, just tricky.

                                                                          Implementing an Erlang runtime in Pony would be similarly tricky, but implementing an Erlang runtime using the Pony runtime (which is available as a C library) would be “relatively easy”, where “relatively easy” means quite hard indeed, but with straightforward semantics.

                                                                          I think the core places where the Pony runtime would be useful to Erlang are in garbage collection of both data structures and actors themselves (unlike Erlang, which requires manually terminating actors, in Pony actors themselves are GC’d with a protocol that allows the runtime to cheaply determine when an actor has no pending messages and can never receive messages in the future) and in code execution (BEAM, while a very impressive VM, doesn’t excel at computational speed, whereas Pony is, surprisingly, a bit faster than C, due mostly to LLVM’s lovely fastcall calling convention, which allows for really good cross-procedure register colouring, plus Pony has aliasing information that’s more useful for optimisations than that available to C).

                                                                          However, Erlang has things Pony doesn’t have (yet). Particularly for distributed computing (although that’s in the pipeline for Pony).

                                                                          tl;dr: Pony has been heavily influenced by Erlang (along with other awesome languages, like OCaml, F#, E, AmbientTalk, Smalltalk/Newspeak, and many others), but they aren’t semantically equivalent.

                                                                    2. 1

                                                                      Thanks for the overview.

                                                                      1. 3

                                                                        There’s more insight into where Pony is trying to go at: https://github.com/CausalityLtd/ponyc/wiki/Philosophy That pages covers general principles and a hierarchy of concerns for the language.

                                                                        I’m happy to discuss more if you want.

                                                                        sean@monkeysnatchbanana.com

                                                                    3. 4

                                                                      By no means an expert, but the short version is that pony has the potential to be radically faster than erlang; has a relatively tiny/nonexistent library set; and is currently for the adventurous.

                                                                      1. 2

                                                                        I bet @seantallen could give you a great overview.

                                                                        1. 1

                                                                          I probably could ;)

                                                                      1. 1

                                                                        The BRASS project http://www.darpa.mil/program/building-resource-adaptive-software-systems is another interesting one (not linked from the above page).

                                                                        1. 3

                                                                          He seems like an interesting designer, as well. If anyone in Chicago would like to try out Pandante, let me know and I’ll get a game together.

                                                                          1. 2

                                                                            I bounced off Sirlin’s Pandante (not open ended like Texas Hold'Em) and Puzzle Strike (not sure what happened, just never felt like we had the game in gear), but his Flash Duel and Yomi are two of my desert island games. I’ve played hundreds of games of each and I feel like I’m just getting started.

                                                                            1. 1

                                                                              Just moved from Chicago to Seattle. Otherwise I would love to! By the way, you know anyone wanting to rent a house near the fox river?

                                                                              1. 3

                                                                                Just moved from Seattle to Chicago! Enjoy.

                                                                                edit: Hey! How is my comment off topic and not mempko’s ? Must be a passive aggressive Seattle downvoter.

                                                                                1. 3

                                                                                  I upvoted you to cancel-out whoever’s downvote. Welcome to Chicago. PM me if you’re looking for tech meetups or anything else.

                                                                                2. 2

                                                                                  What brought you to move to Seattle?

                                                                                  I was planning to move to Seattle in 2014, but ended up finding a better job market in Chicago, and I’m actually quite happy that I landed here (Chicago). With the large finance sector, there’s a very strong adult (30+) job market and it’s nice to be in a big city.

                                                                              1. 1

                                                                                Haxe seems just as compelling as Kotlin. It has

                                                                                • Algebraic Data Types
                                                                                • Pattern Matching
                                                                                • Array Comprehensions
                                                                                • Multiple Backends (Java, C++, JavaScript)
                                                                                • Intellij plugin support

                                                                                http://haxe.org/documentation/introduction/language-features.html

                                                                                1. 7

                                                                                  To be clear, this is within the scope of a single Dept. of Social Services procurement for a new Child Welfare System.

                                                                                  1. 2

                                                                                    This is still huge. Hopefully this will spread to other organizations. Many cul-de-sacs of government are captured by organizations that resell the same low quality custom software. Patient systems, library management, transportation demand management and often the winning bid something like 20% below the actual cost to build.