hellekin | OMFG. OMFG. https://twitter.com/Sysadm_Borat/status/312705773333524480/photo/1 "for loops are for pussies" | 00:45 |
---|---|---|
whitequark | hellekin: I dunno why, but asian embedded really, really frequently features such code | 00:48 |
whitequark | it's not even funny | 00:48 |
hellekin | whitequark: really? Wow. That's scary. | 00:50 |
hellekin | When "don't fix it if it works" doesn't apply, for reason that newbies could start contaminating their code with stupidity. | 00:50 |
whitequark | hellekin: yeah. from a 1.5-second delay for boot led from nops | 00:52 |
whitequark | to literally such unrolled shell loops I've been shown just days ago by a fellow dev | 00:52 |
whitequark | I'd say it's scary for another reason | 00:53 |
whitequark | networked embedded is generally very security-sensitive. and I don't want people writing such code anywhere near anything sensitive. | 00:53 |
hellekin | true | 00:55 |
hellekin | I've never learned coding formally, but I would never even think of doing such horrible code | 00:55 |
hellekin | I'm pretty sure it requires a mouse, because people who knows how to copy-paste with the keyboard cannot be that lazy and stupid. Or can they? | 00:56 |
hellekin | s/knows/know/ | 00:56 |
viric | sure, acn | 00:58 |
viric | can | 00:58 |
viric | people use *fancy* editors for that. | 00:59 |
whitequark | I don't wanna know... | 00:59 |
hellekin | it's even longer to type than the real thing. You gotta be braindead to write such "code" | 01:07 |
hellekin | ah. skip it. There's enough shit in this world | 01:07 |
kyak | viric: it's more clear now for me why you have to create the complete query every time | 17:32 |
kyak | i.e. even if i change one parameter, i send all the others in the form as well | 17:33 |
kyak | it is also clear now why C is not something one should use to handle WEB :) | 17:33 |
kyak | the problem is, you don't have persistent storage.. You fork every time for new request, and children don't have any knowledge about the client's state | 17:34 |
kyak | that is why, the client has to send the complete state every time: "show read", "single page", "local image" and so on.. | 17:35 |
kyak | ..and it took me hell of a lot of time to realize why "extern" variable is reset to 0 every time | 17:36 |
kyak | because of fork, of course | 17:36 |
whitequark | my compiler can now infer types for and compile fib()! | 17:40 |
whitequark | https://gist.github.com/whitequark/2d1d44ed5d97ddc9c933 | 17:40 |
kyak | viric: there is something called a "Persistent CGI", which is probably worth having a look into.. | 17:42 |
larsc | whitequark: nice | 17:42 |
whitequark | larsc: actually you don't see the majority of the interesting things there :D | 17:43 |
whitequark | i.e. how it handles the ruby object system | 17:43 |
whitequark | next on the roadmap are proper machine ints (currently it's a single, degenerate ptr-sized type), and lambdas | 17:44 |
whitequark | the cycle in `main' should look like `10.times { trace fib(10) }' | 17:44 |
whitequark | but compile to exact same code, because why not? | 17:45 |
pcercuei | whitequark: compiler for what? | 17:46 |
whitequark | pcercuei: http://whitequark.org/blog/2012/12/06/a-language-for-embedded-developers/ | 17:46 |
larsc | 10.times ? so you can do like Integer n = 5; n.times { ... }? | 17:46 |
whitequark | larsc: why "Integer n = 5"? just n = 5; n.times { ... } | 17:47 |
whitequark | and yes I can | 17:47 |
whitequark | the compiler features both local type inference by bidirectional dataflow analysis on static single information form and interprocedural type inference via cartesian product algorithm | 17:48 |
larsc | how does the algorithem work? I'm currently working on something very similar for migen | 17:49 |
whitequark | larsc: which one? | 17:49 |
larsc | type inference | 17:49 |
whitequark | well there are two: local and interprocedural :) | 17:49 |
larsc | start with local | 17:49 |
whitequark | it's a distant derivative of Hindley-Milner | 17:50 |
whitequark | my IR is in SSA/SSI form, which can be thought of a purely functional language (SSA is isomorphic to CPS, used in functional compilers) | 17:50 |
whitequark | so HM works perfectly on the SSA values | 17:51 |
whitequark | type unification in canonical HM corresponds to SSA phi nodes | 17:51 |
larsc | the current migen algorithem, if you even can all it that, is dead stupid. just tries to derive the type 'for' each signal in a loop until each signal has one | 17:51 |
whitequark | larsc: HM is not significantly more clever | 17:51 |
whitequark | but it can handle conflicts | 17:51 |
whitequark | like e.g. if foo; 1; else "2"; end | 17:52 |
whitequark | the HM-derived resulting type would be Integer|String | 17:52 |
whitequark | what I do in these cases is restrict the resulting unions so that runtime perf would be manageable | 17:53 |
whitequark | TrueClass|FalseClass is reduced to Boolean (internal, not ruby type) | 17:53 |
whitequark | Base|Derived is reduced to Base | 17:53 |
whitequark | UnrelatedA|UnrelatedB is reduced to Object, well, because everything inherits from Object | 17:53 |
larsc | makes sense | 17:54 |
whitequark | also NilClass|Whatever is reduced to nullable<Whatever> | 17:54 |
whitequark | and that's mostly all | 17:54 |
whitequark | otherwise you would end up with union types which would require essentially dynamic dispatch | 17:54 |
whitequark | and perf will go nowhere | 17:54 |
whitequark | also I handle types for mutable local bindings in a very similar fashion | 17:54 |
larsc | mutable local bindings? | 17:55 |
whitequark | aka "variables" :) | 17:55 |
larsc | ah, ok | 17:55 |
whitequark | the kink with local variables is that they're mutable and HM is purely functional | 17:55 |
whitequark | loop { a = 1; a = "2" if rand > 0.5; p a } | 17:56 |
viric | kyak: I fork in offrss because I don't want memory leaks | 17:56 |
whitequark | larsc: now there's also upwards DFA, which handles closures | 17:56 |
whitequark | see, the type of a closure is derived from its usage, as opposed to definition | 17:57 |
viric | kyak: and it's a matter of taste, when to fork. | 17:57 |
whitequark | larsc: def loop(&block); while true; block.call(); end; end | 17:57 |
viric | kyak: I fork at the very start, because it's like CGI. I don't think I need much persistent storage. Does it run slow for you? | 17:57 |
whitequark | larsc: as you can see this method has a well-defined type of `block', but downwards DFA could not infer it... | 17:58 |
whitequark | larsc: the other clever thing one could do with bidi-DFA is latent predicates | 17:59 |
whitequark | larsc: for example this: def foo(bar); if bar.is_a?(Integer); bar + 1; else nil; end; end | 17:59 |
whitequark | larsc: without #is_a?(Integer), the method could not typecheck if I pass a String there | 17:59 |
whitequark | *would | 18:00 |
larsc | i see | 18:00 |
kyak | viric: nah, it's not slow at all. I just don't like the way you have to construct the complete query (i.e. configuration) every time | 18:00 |
whitequark | larsc: it's like pattern matching from haskell, but with none of the monads :D | 18:00 |
kyak | viric: it looks redundant in C code, and you have to think about the complete configuration all the time | 18:01 |
whitequark | larsc: now, interprocedural inference is even simpler. imagine that every function, initially, has a polytype where each argument is assigned its own type variable | 18:01 |
kyak | viric: why am i even talking about - i'd like to have "mark all as read" button, and the design is such that it can't be easily extended | 18:01 |
viric | kyak: I could use a cookie. But I never learnt cookies | 18:01 |
whitequark | larsc: forall(a,b) Integer#+(a self, b other) | 18:01 |
whitequark | larsc: note how self doesn't have a monotype either. this is because you can inherit from Integer, and in the derived class self would not have the type Integer | 18:02 |
viric | kyak: yes, web without cookies is harder. :) Maybe they'd really simplify all | 18:02 |
whitequark | larsc: now, if you encounter a call, say, (Fixnum < Integer) Integer#+(Fixnum 1, Fixnum 2), you specialize the method for that particular call site. | 18:03 |
viric | kyak: but then the state is not per browser window, but per browser. | 18:03 |
larsc | whitequark: what does #+ do? | 18:03 |
whitequark | larsc: addition | 18:03 |
whitequark | 1 + 2 | 18:03 |
whitequark | # is just a separator between class name and method name. | 18:03 |
larsc | and the hash means that it's a method of the type... ok | 18:03 |
whitequark | larsc: so, now instead of a method which can accept anything you have a method which only accepts Fixnums | 18:04 |
whitequark | so you can eliminate a ton of redundancy. type checks, range checks (sometimes), etc. you can do inlining. it's awesome actually | 18:04 |
whitequark | you can do partial specialization. say if you don't know what the second argument is, you infer forall(a) Integer#+(Fixnum 1, a var) | 18:04 |
whitequark | you still can eliminate half of the redundancy and maybe inline the method | 18:05 |
whitequark | and the algorithm is closed over composition, that is, you can specialize the methods over and over again if you know more and more about your code | 18:05 |
kyak | viric: i'll try to implement that button, and we'll see how it goes. If it turns into a monster, perhaps it's a good sign to rewrite server.c :) | 18:05 |
whitequark | larsc: what's even more interesting is what happens when you get to parametric types. you can do restrictions on type variables! | 18:06 |
whitequark | say we have a generic List | 18:06 |
whitequark | forall(a) List#append(List<a> self, a elem) | 18:06 |
viric | kyak: ok :) think of a cookies model if you want | 18:07 |
whitequark | larsc: this method can be specialized for any element type, but only ones which match the type of the list | 18:07 |
whitequark | what actually happens is that | 18:07 |
whitequark | you speculate that you can specialize this method for List<Integer>, so you basically replace a with Integer | 18:07 |
whitequark | then, if the result, being substituted at the original callsite, still typechecks, this means we're good | 18:08 |
whitequark | otherwise someone screwed up :) | 18:08 |
larsc | so what does forall do? | 18:08 |
larsc | is it a predicate? | 18:08 |
whitequark | hah, I actually have this on my compose key | 18:09 |
whitequark | yes. | 18:09 |
whitequark | it does not figure in the language syntax itself, of course (neither does `#'); I'm using this because it's common notation | 18:09 |
kyak | viric: i just want to make it completely clear. For example, when i click the yet-to-be-implemented "mark all as read" button, i need to send not just the state of this button, but also all the other states - like "show read", "local images" etc. Otherwise, the state of the client (my web browser session) would become inconsistent. For example, clicking this button would reset the "local images" button state | 18:10 |
whitequark | you can think of it as a type constructor, if that's simpler. »’a.List<a>’a’List<a> | 18:10 |
larsc | yea | 18:11 |
viric | kyak: I think you are not very used to web programming :) | 18:11 |
whitequark | larsc: ok. so. when you already have types dependent on terms, you can add types dependent on values! | 18:11 |
viric | kyak: or are you? | 18:11 |
whitequark | for example forall(Integer a) MachineInt<a width> | 18:12 |
whitequark | you see where it goes :) | 18:12 |
larsc | no | 18:12 |
whitequark | ok | 18:12 |
viric | kyak: I mean... one think would be to have a persistent storage based on some id, that identifies the browser windows. But that's not very common I think; Most people use cookies, and cookies are per browser and not per window. | 18:12 |
whitequark | larsc: MachineInt is a generic class, but it does not accept a type as its parameter, but a value (constant number) | 18:12 |
viric | kyak: giving weird results if you have multiple windows on the same served pages. | 18:12 |
whitequark | larsc: the intended result is that we can get to manipulate this number both in the type system, as if it were a type, and, say, typecheck machine int addition: | 18:13 |
viric | kyak: but persistent storage would allow to pass only an id instead of all. But whether it's hard to send an id or send all, is a matter of good programming. Of course I wrote offrss with some kind of 'minimal effort for what I need'. I'll see if I can improve what you want. :) | 18:13 |
whitequark | larsc: forall(Integer a) MachineInt#+(MachineInt<a> self, MachineInt<a> other) | 18:13 |
kyak | viric: i have no idea why you start talking about browser windows. I'm only talking about one window, or one tab now | 18:13 |
viric | kyak: yes, but multiple tabs has to work too | 18:14 |
viric | (at least, I want it to work) | 18:14 |
viric | :) | 18:14 |
viric | well, I'm sorry but I've to leave now. Tomorrow more! | 18:14 |
larsc | hm | 18:14 |
viric | kyak: I quite finished a recent project that took my time, and I can get into it | 18:14 |
whitequark | larsc: *and* also as a value. for example: class MachineInt; def <<(Integer bits); raise ArgumentError if bits > @@width; ...; end; end | 18:14 |
viric | ?>:0! | 18:15 |
kyak | ?>:0 :) | 18:15 |
whitequark | larsc: (@@width would be a Ruby syntax to extract the value from the corresponding type parameter) | 18:15 |
larsc | ok | 18:15 |
whitequark | larsc: so, as you can see, we take here a type, governed and enforced by type system rules, and compare it with a user-provided value! | 18:15 |
whitequark | (in order to prohibit shifts too wide to handle, or whatever) | 18:16 |
whitequark | now, the most interesting part of this everything is how it works with Ruby metaprogramming | 18:16 |
whitequark | and the answer, it works so well that C++ programmers will die from envy :) | 18:17 |
larsc | hehe | 18:17 |
whitequark | a Ruby class is a type; a Ruby class is also a value; the type system can represent and work with both classes and plain old data | 18:17 |
whitequark | and you can directly manipulate everything of this with just Ruby code | 18:18 |
whitequark | so, if you need a friggin' compile-time loop, you go and write `while' there. no weird template magic attached | 18:18 |
whitequark | if you need to define a method derived from some other runtime property, here you are | 18:18 |
whitequark | dynamically generate constant? ok | 18:18 |
whitequark | so we have a language which is as fast as C++, strictly more powerful and way easier to write in :D | 18:19 |
whitequark | also if you're going to do something similar, please note that type variables are only a property of, and attached to, and have sense in the context of functions. | 18:21 |
larsc | and I guess you'll be able to attract ruby programmers | 18:21 |
whitequark | larsc: that is the point. Ruby, Python, JS, *and* C++ (because some of them do have sense) | 18:21 |
whitequark | the main reasons I chose Ruby as the base for the language are: 1) it is quite well-known 2) sensible, Smalltalk-derived OO model, unlike Java/C++ 3) easy and mostly quite logical metaprogramming | 18:23 |
whitequark | 3) is a total clusterfuck in python | 18:23 |
larsc | tried that today | 18:23 |
whitequark | that didn't stop someone from writing a thing similar to mine called Starkiller as a phd project | 18:23 |
whitequark | it is however too academic to be usable | 18:24 |
whitequark | WAY too academic. | 18:24 |
whitequark | ruby's syntax is sometimes really meh (seriously, \C-? in the core of the language?!), but I can fix that | 18:25 |
whitequark | ruby's stdlib is sometimes (quite rarely) weird, but that's simple and I will fix that | 18:25 |
whitequark | whoever wrote Encoding support was high on something evil | 18:26 |
whitequark | oh some other features I have for free in ruby: | 18:26 |
whitequark | - interpolations. if you write stuff like "this is a long format string: #{foo.to_s}" then what happens? the first part of the long format string is stored in the .rodata; result of foo.to_s is calculated; these two are combined into a rope. | 18:27 |
whitequark | ... which is an implementation detail completely transparent to user code, because user code iterates strings with #each | 18:27 |
whitequark | so you can have *very* efficient iteration which is also flash-friendly | 18:27 |
larsc | but also means that strings are a core feature of the language | 18:28 |
whitequark | they are indeed | 18:28 |
whitequark | even more; in Foundry, UTF-8 is a core feature of the language. (Unless you disable it, but I advise strongly against.) | 18:28 |
whitequark | it stores data in UTF-8 to save space and iterates it as UTF-16 or UTF-32 (machine words are 32-bit anyway). corner cases such as surrogate pairs are already handled. | 18:30 |
larsc | I guess one advantage when you are dealing with hdl languages is that all objects are instantiated at synthesis time, so you don't have to deal with unions | 18:30 |
whitequark | larsc: indeed | 18:30 |
whitequark | HDL is much more declarative than Foundry | 18:30 |
whitequark | it's *completely* declarative D: | 18:30 |
whitequark | *:D | 18:30 |
larsc | although it could come in handy knowing which types are compatible, so you can do time multiplexed sharing of blocks | 18:30 |
whitequark | yea | 18:30 |
whitequark | larsc: one thing I was also thinking about is deeply integrating regexps within compiler | 18:31 |
whitequark | so that during compilation it would generate the optimal state machine | 18:31 |
larsc | uh | 18:31 |
larsc | yea, precompling the regex may make sense | 18:31 |
whitequark | you could then trivially parse URIs or HTTP or whatnot; flex is essentially a regexp -> state machine generator either. | 18:31 |
whitequark | it can simply invoke ragel and then link the result, as I'm ABI-compatible with C | 18:32 |
whitequark | and LLVM's LTO means that it won't generate cruft on the boundary | 18:32 |
larsc | isn't there this google lib for efficent regexes? | 18:32 |
whitequark | larsc: hm, not sure | 18:32 |
whitequark | ruby uses oniguruma. a ruby parser in oniguruma is 2x slower than ruby parser in flex+bison | 18:33 |
whitequark | which I guess means that oniguruma is a hell of a fast library | 18:33 |
larsc | re2 | 18:34 |
larsc | a nfa based regex implementation | 18:35 |
whitequark | yea I see | 18:35 |
whitequark | I wonder if I can disembowel it and generate LLVM or C from the result | 18:36 |
whitequark | http://lwn.net/Articles/378440/ | 18:37 |
whitequark | actually, ragel can simply emit ruby code, which I can compile | 18:41 |
whitequark | no need in anything extra... | 18:41 |
whitequark | bbl | 18:44 |
paul_boddie | whitequark: You mentioned Starkiller, but did you look at Shedskin? | 23:11 |
Action: paul_boddie knows that whitequark always checks the logs. | 23:16 | |
--- Sun Mar 17 2013 | 00:00 |
Generated by irclog2html.py 2.9.2 by Marius Gedminas - find it at mg.pov.lt!