<kaustuv>
Summary: Java over twice as fast as ocamlopt on GC-heavy microbenchmark, even though the latter runs on a faster machine
<flux>
are mac os x binaries always 64-bit?
<flux>
kaustuv, you mean mutable updates are much faster in java compared to mutable updates in ocaml?
<flux>
because it doesn't look that GC heavy anymore to me
<kaustuv>
That too, but I find the mutable Java faster than immutable OCaml native to be the more shameful result
<mrvn>
what does changing a mutable involve in ocaml?
<kaustuv>
Well, a call to caml_alloc_double(), which might explain it.
<flux>
I imagine Java has much chances for producing faster code, given JIT and the amount of work that has been done for making it fast
<mellum>
I think what we mostly learn from this is "microbenchmarks are useless"
<mrvn>
kaustuv: I ment generally.
<kaustuv>
generally it's just overwriting an integer or a pointer
schme has joined #ocaml
<flux>
doubles are unboxed in java
<kaustuv>
I think the problem is that x +. 1. actually has *three* calls to caml_alloc_double()
<kaustuv>
(or two, depending...)
<mrvn>
kaustuv: huh? That should unbox.
<flux>
I suppose it'd be technically possible to unbox any basic data type in a record, other than it would break C interface
<mrvn>
kaustuv: how does the GC catch when a mutable is changed? mprotect or does the changing code notify the gc?
<kaustuv>
yeah, doubles are always boxed in records (currently) unless the record contains only doubles
<kaustuv>
mrvn: there is a write barrier: Store_field()
<mrvn>
flux: x +. 1. should not allocate a box for the 1., only for the result.
<kaustuv>
It won't on amd64, but I think it will on x86
<kaustuv>
(because it doesn't use the fp registers)
<mrvn>
which just means the compiler is crap.
<flux>
mrvn, but still, it needs to dereference the reference first before it can do actual work, and allocate a box for the result?
<mellum>
well, coding x86 FP is not fun. And probably not worth bothering anymore.
<mrvn>
flux: unless it can proove that the box is not used, e.g. let x = ref 0. for i = 1 to 10 do x := !x +. 1.; done;;
<flux>
mrvn, right, didn't think of that. if that kind of optimization was done, then let a = foo.float_field would need to result in a copy
<flux>
I wonder though which approach would in general be a win
<mrvn>
Thing what happens if you have registers: At the begining of the loop x gets copied into a register, the loop changes the register and at the end the register is written out to a fresh box.
<mrvn>
On x86 fp register means a spot on the fp stack. But the idea is the same.
<mrvn>
flux: not allocating boxed in inner loops is a huge win.
<thelema>
mrvn: not allocating anything in inner loops is huge win
<mrvn>
I would even say that register allocation is the one most important optimization you can do. The first thing you should do.
verte has quit ["~~~ Crash in JIT!"]
<kaustuv>
Allocaing blocks of four words that immediately die should be pretty cheap.
<mrvn>
kaustuv: the writing/reading of the memory costs a ton.
<kaustuv>
Sure, but that's unavoidable when you have mutable fields.
<mrvn>
kaustuv: no. that is exactly what gets optimized away.
<kaustuv>
Ain't no register allocator on the planet that can optimize a reference cell
<mrvn>
kaustuv: look at the example above. you don't want to write 1. to memory.
<mrvn>
kaustuv: and in the look you only write the end result to memory.
<kaustuv>
Ah, right, if that's what you meant, I agree.
<mrvn>
s/look/loop/
<mrvn>
Obviously for i = 1 to 10 do x := !x + 1; foo x; done needs to write x out every time generally. But that is different.
angerman has joined #ocaml
<mrvn>
Thanks to cross module inlining ocaml could optimize code like that a lot more than C/C++ can.
<thelema>
mrvn: thanks to pervasive use of preprocessor macros, C/C++ gived better performance than ocaml because one can insist the compiler expand your functions (across files even) and then apply huge rewrites to it.
<mrvn>
thelema: only with macros or static inline in the header. I was thinking different compilation units.
<mrvn>
The problem with forcing it is that you can just as easily be wrong as right.
<thelema>
true, but you can use the scientific method to find out which and act accordingly. The compiler can't.
<mrvn>
thelema: there are good heuristices for compilers. for within a compilation unit gcc does a good job there.
olegfink has quit ["WeeChat 0.2.7-dev"]
<thelema>
all those heuristics end up making the compiler sensitive to its input in ways that shouldn't matter, no? If some code fits a certain pattern, optimization X kicks in and makes it fast. But code that's almost the same won't trigger the optimization
olegfink has joined #ocaml
<mrvn>
thelema: size of function, number of opcodes in function, estimate of number of calls to function. You already have all that in the inline decision making.
<thelema>
# of calls to the function?
<mrvn>
thelema: if it is called from 10 places then inlining would take 10 times the space than calling it.
schme_ has joined #ocaml
<thelema>
does a function have to be inlined everywhere it's used?
<mrvn>
nope
<thelema>
I'd imagine the decision to inline as more of a case-by-case basis.
<mrvn>
sure.
<thelema>
I admit that you lose on code size if you inline n-1 times, and still keep the original function
<thelema>
but you're inlining. you always lose on code size
<mrvn>
thelema: not true.
<mrvn>
calling let f x y = x + y costs more than just adding the 2 registers.
<thelema>
overhead on parameter passing boilerplate?
<mrvn>
or method get_foo = _foo
sgnb has quit [Read error: 60 (Operation timed out)]
patronus has quit [Read error: 60 (Operation timed out)]
sgnb has joined #ocaml
patronus has joined #ocaml
toocrazy has joined #ocaml
schme has quit [Read error: 110 (Connection timed out)]
seafood has quit []
acatout_ has joined #ocaml
julm has quit [Read error: 110 (Connection timed out)]
Camarade_Tux has joined #ocaml
julm has joined #ocaml
acatout has quit [Read error: 110 (Connection timed out)]
willb2 has joined #ocaml
bombshelter13_ has joined #ocaml
Smerdyakov has joined #ocaml
Camarade_Tux has quit ["Leaving"]
toocrazy has quit ["Ex-Chat"]
Camarade_Tux has joined #ocaml
Smerdyakov has quit ["Leaving"]
willb2 has quit ["Leaving"]
Smerdyakov has joined #ocaml
jm has joined #ocaml
acatout_ is now known as acatout
julm has quit [Read error: 110 (Connection timed out)]
jamii has joined #ocaml
komar_ has quit [Read error: 113 (No route to host)]
komar_ has joined #ocaml
Smerdyakov has quit ["Leaving"]
Camarade_Tux has quit ["Quitte"]
willb has joined #ocaml
mattam has joined #ocaml
jeanbon has joined #ocaml
vpalle has joined #ocaml
Associat0r has joined #ocaml
robocop has joined #ocaml
<robocop>
hello.
<robocop>
I've got a little question about Ocamllex. If we want all string different of "foo", what's the regex ? (['a'-'z']+ \ "foo")
<robocop>
I trying ['a'-'z']+ ^["ta mere"]
<robocop>
but dosn't work.
<robocop>
*doesn't
itewsh has joined #ocaml
jeanbon has quit [Read error: 110 (Connection timed out)]
<mrvn>
when I have a big module and only use one function does the compiler only put that one function into the binary or all of the module?
<jeff_s_>
the whole module I think. at least it looks that way after I compile a program that contains large libraries like Unix and Str
<mrvn>
that sucks.
<mrvn>
I have programs, one creates an FS, the other runs it with fuse. The mkfs only needs a small subset of the code and I would rather have that small.
<mrvn>
Might be worth it to create small.ml and big.ml which includes Small.
<mrvn>
Biggest blemish currently is that mkfs is linked against libfuse and libaio. Two things it shouldn't need.
Ched has quit [Read error: 110 (Connection timed out)]
<mrvn>
That way "in" looks like an argument to inode.
<det>
well, with syntax hilighting it doesnt
bombshelter13_ has quit []
<mrvn>
I do a line break before "then" and "else" and short expressions in the same line as "then" or "else".
<julm>
thelema: about this morning's discussion, I think that should be possible to use .cmi as a module type, if I use cmigrep everything seems to be in the .cmi to do it; and I'm 99% sure it has been possible a year ago.
<mrvn>
Single line let get in in the same line except the last in a block and multi line let always in in its own line.
<mrvn>
foo(x,y,z) doesn't work well with currying.
<det>
I prefer tupling
<det>
and I find f(x) easier to read to "f x"
<mrvn>
foo(x), foo(x, y) and foo(x, y, z) should be possible and they are different from foo((x, y, z))
<det>
and more consistent when you are using tuples
<det>
foo(x,y,z) is the same as foo((x, y, z))
<mrvn>
det: Not with currying.
<det>
both of those examples have 1 argument
<mrvn>
det: the first passed 3 args, the second one tripplet.
<det>
in your hypothetical syntax maybe
<mrvn>
det: in your python like syntax with currying.
<det>
I wouldnt have currying
<det>
comma would be tupling operator
<mrvn>
det: that is a major part of functional languages.
<det>
I dont agree
<mrvn>
det: would you write f(x)(y)(z) for a function with 3 arguments?
<det>
You would use a tuple!
<det>
look at SML
<mrvn>
det: one with currying
<det>
Why would it be curried ?
<mrvn>
det: because that is often verry usefull
<det>
Not in my experience
<mrvn>
I use partial application all the time.
<Yoric[DT]>
FWIW, in OPA, we're writing [f(x,y,z)] rather than [f x y z].
<Yoric[DT]>
And we have a syntax for partial application.
<det>
I was gonna say, I would probably add a syntax for partial application
<Yoric[DT]>
[f(x,_,z)] is [fun y -> f(x,y,z)]
<det>
but I dont feel partial application neccesarily better than just using a lambda
<det>
Yoric[DT], what is OPA
jeanbon has quit [Read error: 110 (Connection timed out)]
<mrvn>
det: so far in yur python like syntax let f = function x -> function y -> function z -> x+y+z would give f(x)(y)(z)
<Yoric[DT]>
Well, partial application of *any* argument is nice to have.
<Yoric[DT]>
det: the language we're currently developing.
<det>
Yes, that is major advantage
<Yoric[DT]>
Functional + concurrent programming for the web.
<det>
currying is for partial application is a hack IMO
<olegfink>
Yoric[DT]: sorry for jumping in the middle of a dicussion, is the partial application in OPA or in ocaml?
<mrvn>
Yoric[DT]: I can live without partial application if you keep returning functions. That would just mean you have to curry things manually where usefull.
<Yoric[DT]>
olegfink: I beg your pardon?
<det>
people design their libraries (argument order) to opitmize partial application and they sometimes get it wrong anyways
<olegfink>
er, okay, I figured.
<mrvn>
Yoric[DT]: but ocamls "fun" is so much more fun that function
<olegfink>
partial application is one of the things I like most about K.
<Yoric[DT]>
mrvn: :)
<Yoric[DT]>
olegfink: what does it look like in K?
<mrvn>
det: you learn and you improve.
<olegfink>
f[x;;z]
<det>
It is a really bad way to design libraries IMO
<Yoric[DT]>
mrvn: I don't know, returning functions manually is inelegant
<mrvn>
Yoric[DT]: sure. but it must be possible.
<Yoric[DT]>
det: yes, one of the reasons why partial application in OPA does not require currification
<mrvn>
det: that still leaves you with f(x)(y)(z) to call it.
<det>
Tupling is much more consistent with a language like Ocaml
ztfw` has quit [Remote closed the connection]
<det>
Mrvn, I wouldnt advocate currying in the first place
<mrvn>
det: note that in ocaml you can write f(x) or f(x,y,z) just fine.
<det>
but instead tuples + partial application syntax
<det>
mrvn, your performance will suck
<mrvn>
det: suggest one that doesn't end in f(x)(y)(z)
<mrvn>
det: hugh? adding () in ocaml make no difference
<det>
f(x, y, _) ?
<olegfink>
I always wondered why SML, being such a close language to ocaml, almost always prefers tuples to currying in the library
<det>
Mrvn, tupling does
<mrvn>
det: doesn't work with f from above.
itewsh has quit [Read error: 110 (Connection timed out)]
<det>
Look at ocaml:
<det>
functions return multiple arguments with tuples
<olegfink>
Yoric[DT]: the other cool thing in K is anonymous recursive functions without Y.
<mrvn>
det: f is defined as function taking one argument. You used it as function taking 3 where one is missing.
<det>
constructors (like 'a option) need tuples, cant work with currying
itewsh has joined #ocaml
<Yoric[DT]>
olegfink: sounds nice
<Yoric[DT]>
olegfink: how do they do it?
<mrvn>
Yoric[DT]: implicit let rec func = before closures.
<olegfink>
well, it looks a bit hackish, let's say they have a keyword _f that means 'the innermost function'
<Yoric[DT]>
olegfink: ok, that's cheating :)
<det>
mrvn, "f(x, y, _)" could be syntactic sugar for "fun(z): -> f(x, y, z)"
<det>
erm
<det>
mrvn, "f(x, y, _)" could be syntactic sugar for "fun(z): f(x, y, z)"
<olegfink>
Yoric[DT]: well, about the level of java's 'this'.
<mrvn>
(fun x -> fn x) becomes let rec fn = fun x -> fn x
<det>
where fun is anonymous function
<olegfink>
but then you can have no 'let rec'
<Yoric[DT]>
olegfink: well, look at java's "Foo.this" :)
<mrvn>
det: but f is a function expecting one argument.
<mrvn>
det: and returning another function
<det>
mrvn, it is just syntax
<det>
as in, one ast replaces another
<mrvn>
det: let g = f(x,y) should be possible.
<det>
yes
<det>
g = f(x, y, _)
<det>
more obvious that you are partially applying
<mrvn>
det: your syntax would require let g = f(x,y,_)
<det>
mrvn, what is wrong with that ?
<olegfink>
Yoric[DT]: er, what's that?
<mrvn>
det: you might now know how many arguments are to follow.
<olegfink>
K is all about cheating, but it's damn sexy cheating.
<Yoric[DT]>
olegfink: when you write a class inside a class, you sometimes need to specify which "this" you're actually using.
<det>
mrvn, I don't :-)
<mrvn>
det: but you need to to infere the right tupple kind.
* Yoric[DT]
actually prefers [let g = f(x,y,_)] to [let g = f(x,y)] there.
<det>
you don't it is just syntax
<mrvn>
Yoric[DT]: the _ might be dependant on x or y.
<Yoric[DT]>
mrvn: what do you mean?
<mrvn>
Yoric[DT]: depending of the type of x there might or might not be a _
<Yoric[DT]>
mrvn: I don't quite follow.
<det>
mrvn, I don't know why you say that
<mrvn>
let f x y = x let g x y = f(x,y,_) would have to infere that x : 'a -> 'b
<mrvn>
but I guess that is no more complicated than let g x y z = f x y z
<olegfink>
{:[x=0;1;x*_f[x-1]]} 5
<olegfink>
120
<olegfink>
isn't that sexy? :-)
<mrvn>
olegfink: ; is used to mean different things => bad
<olegfink>
Yoric[DT]: so OPA has no currification at all?
<det>
mrvn, I still dont understand why you say that
<mrvn>
{:[x=0 -> 1; x* -> _f[x-1]]} 5 would be better
<olegfink>
mrvn: ( is used to mean different things.
<det>
mrvn, you can write "f(x, y, ))"
<olegfink>
e.g. (a+b) or a.(b)
<mrvn>
olegfink: in ocaml ( always means the same except for ()
<mrvn>
olegfink: ups, yeah, you are right.
<olegfink>
oh, and () too
<det>
mrvn, or you can write "fun(z): f(x, y, z)"
<det>
same thing
itewsh has quit ["There are only 10 kinds of people: those who understand binary and those who don't"]
<olegfink>
:[ ; ; ] is a syntactic construct, so it's not much worse than ocaml.
<mrvn>
Anyway, the f x y z syntax in ocaml is one thing I love.
<det>
olegfink, I don't find that sexy :-)
<det>
ok, maybe you prefer that syntax, I can accept that
<det>
But I have not seen any valid arguments of why currying is better for functional languages
ergodick has joined #ocaml
<det>
and I have made given cases of why tupling is superior
<olegfink>
mrvn: this syntax wasn't possible for a vector language, so you only get f x; f x y z is f (x;y;z) (a list of three items)
<mrvn>
det: f(x,y,z) visually implies the function takes exactly 3 arguments, f x y z is much more open imho.
<mrvn>
det: (if x then f else g) 17
<mrvn>
as oppsoed to (if x then f else g)(17)
<det>
I find the latter more clear :-)
<det>
but noone would ever write code like that
<mrvn>
or f((1,2),(3,4))(5,6)
<mrvn>
*shiver*
<olegfink>
K gives a good rationaly for the latter syntax: application and array(list) indexing are the same operation
<olegfink>
rationale even
<det>
You are giving examples of how to intentionally write hard to read code
<mrvn>
det: yep.
<det>
and f is using currying
ergodick has left #ocaml []
<det>
which I already stated wouldnt exist :-)
<mrvn>
det: no, let f = function (x,y) -> function z -> x+y+z
<det>
yes
<det>
you could do it
<det>
But noone would
<mrvn>
det: yes they would.
<olegfink>
so, to pick the discussion chilly, what about on of the more controversial k features: default function argument names? :-P
<det>
Do you see a lot of currying in Python ?
<det>
you can curry in Python
Camarade_Tux has joined #ocaml
<mrvn>
det: think of let f x y = let t = do_somethin_expensive x y in function z -> t z
<Yoric[DT]>
olegfink: we haven't fully decided yet, but I advocate that we shouldn't have currification since we have another, more general, mechanism.
<Yoric[DT]>
Still, time to call this a night.
<Yoric[DT]>
Cheers.
<mrvn>
det: let g z = f 1 2 z
Yoric[DT] has quit ["Ex-Chat"]
<mrvn>
det: precalculation some data when doing partial application and then using the restulting function many times is a powerfull tool.
<mrvn>
det: real world examples would be compiling regexp before searching for them.
<det>
But you can abstract it is more obvious ways
<det>
rexp = Re.compile("[a-zA-Z]+")
<mrvn>
det: then you need to always explicitly compile the regexp.
<det>
Re.match(rexp, "fsdfsdfsdfsd")
<det>
I dont find that problematic
<det>
I like that it is obvious that there is staging going on
<mrvn>
I find it nicer that the module can define Re.match in a way that does it implicitly.
ikaros has quit ["Leave the magic to Houdini"]
<det>
But then you dont know where and if the staging happens
<mrvn>
det: so? the result is the same. It is just an optimization.
<olegfink>
hm, i absolutely agree i can write ocaml c- (or how they say nowadays, python)-style, but why if there are mechanisms for doing it with clean semantics?
<olegfink>
det: isn't that all that high-level stuff is about?
<det>
It should be obvious when an expression actually *does* stuff
<det>
also, in this case, currying is less useful
<olegfink>
well, I sometimes like the ability of ocaml to be a pure language, and a pure language has computation only as an implementation detail.
<det>
because you can only used the curried function for that specific function
<det>
where you can use a compiler regex for matching/searching/splitting/etc
<det>
compiled*
<olegfink>
yes, I agree that makes more sense in a language with implicit memoisation, but does that mean it's useless in ocaml?
<det>
that what is useless
<olegfink>
currying?
<mrvn>
I use currying, functions as return values and partial applications a lot. That's what makes ocaml such fun.
<det>
I wouldnt mind using explicity eta expansion in place of partial application
<det>
ie:
<det>
let sum list = List.fold_left (+) 0 list
<det>
instead of
<det>
let sum = List.fold_left (+) 0
<mrvn>
det: Also note that "let g = f" and "let g x = f x" type differently in ocaml.
<mrvn>
(I don't quite get why but that is how it is :)
<olegfink>
mrvn: example?
<mrvn>
Can't recreate one now but I got '_a -> '_a vs. 'a -> 'a earlier tonight.
<det>
value restriction
<det>
that is actually an argument against currying
<det>
eta expansion solves it
<olegfink>
I don't know why but the monomorphism restriction is explicitly annoying in haskell.
<mrvn>
What I miss in ocaml is varian and record prefixes.
<mrvn>
s/varian/variant/
<olegfink>
(do I understand correctly that this is the same thing?)
<det>
I like SML records
<det>
olegfink, they are different
<mrvn>
olegfink: '_a can be anything but only one thing. Once used with a type it can only be that type. sucks.
<olegfink>
er, I'm mixing english words.
<det>
mrvn, with partial application syntax I proposed, you'd never have that problem, since it is just syntax for eta expansion
<det>
The regular expression example is actually a good example of how currying can hurt an API design. Some clever Ocamler used currying + staging to hide the compile step, but now you have no way of sharing big regular expressions across different operations.
<mrvn>
det: sure you do. regexp are lazy and once compiled remain compiled.
<det>
let matcher = Re.match "[a-zA-Z]+"
<det>
what if I want to use that regular expression to do searching ?
<det>
or splitting or some other operation
<mrvn>
det: let regexp = Re.make "[a-zA-Z]+"; let matcher = Re.match regexp let searcher = Re.search regexp
<det>
mrvn, but you are now not using currying
<det>
well
<det>
you are
<det>
but not in the way your proposed
<mrvn>
det: no. that was just an example.
<det>
But your whole argument was that currying lets you hide the compile step
<mrvn>
det: which is not always the best implementation for every case
<olegfink>
det: I'd say currying makes it easy to write in compositional style, like it's common in haskell.
<det>
You are now just duplicating the API which I said was more obvious
<olegfink>
foo = bar baz . bah
<olegfink>
otherwise you'll have to write all the arguments to all the functions
<det>
Can you give a real world example?
<mrvn>
det: the problem I have with your style is that f(x)(y)(z), f(x,y)(z), f(x)(y,z) and f(x,y,z) must all be possible and mean the same.
<mrvn>
In ocaml it is always just f x y z.
<det>
mrvn, that's not true
<det>
in my langauge all functions would still be 1 argument -> 1 result
<mrvn>
det: which can be another function
<det>
those things are all clearly different
<det>
Ok, I see what you are saying
<mrvn>
let f x = x; f((fun y -> y), 1) -> 1
<mrvn>
f(fun y -> y)(1) -> 1
<mrvn>
let g = f(fun y -> y) in g(1)
<det>
But I dont see why you would just write 3 -tuple function in the first place
<mrvn>
to make it obvious that it is multiple applications
<det>
why you wouldnt*
<mrvn>
det: the f is polymorphic. You don't know how many args it gets
<olegfink>
det: do you prefer production code or, say, icpc jury solutions?
<det>
olegfink, what does ippc jury solutions represent
<det>
Im not familiar with icpc
<olegfink>
typical code for solving algorithmical problems
<det>
I guess I don't know what you are asking
<olegfink>
hah, I can't find haskell solutions :-)
<mrvn>
My mini FS already has 750 LOC and I can't mkdir, rmdir, unlink and rename yet.
<mrvn>
I probably won't get it done in <1000 LOC. :(
Dylan16807 has joined #ocaml
hkBst has quit [Remote closed the connection]
<mrvn>
Lets write the next 750 LOC tomorrow. n8.
<olegfink>
det: well, after looking at 'real world haskell' which contains many code snippets written this way, the most obvious use for currying is List.map and friends