|
![](/i/fill.gif) |
On 16/05/2011 20:18, Darren New wrote:
> On 5/16/2011 1:06, Invisible wrote:
>> Well, no. See, if you call a Win32 function, it just works. If you call a
>> function that you wrote yourself, you have to tell the linker to link the
>> corresponding object code.
>
> Unless you register it, I expect.
Well, no, what I'm saying is that if you call a function that's defined
in (say) windows.h, the linker somehow "finds" it. But if you wrote some
C source code of your own, you have to tell the linker to link in the
object code or it complains it can't find it.
It makes sense that you have to tell the linker where to find your own
code. What I can't figure out is how it somehow "knows" when a function
is from the Win32 API and magically finds it.
(The answer is probably something like "GHC automatically includes the
Win32 files at link time".)
>> As I understand it, calling Win32 works by calling a C stub function
>> which
>> does the necessary machine code magic to actually invoke the Windows
>> kernel,
>> whatever that may be. But I don't see anywhere where this gets linked
>> in...
>
> It's entirely possible the declaration itself generates that code, isn't
> it? I'm pretty sure that's how it works in C#: you say "C# XYZ(i) calls
> C-languge PDQ with a (short) parameter" and the compiler generates an
> XYZ function that casts its argument to a short and jumps to the PDQ
> function, basically.
If I do a "foreign import", the Haskell compiler generates a Haskell
function which calls the corresponding C function. Which is fine if
you're statically linking the C code into your binary. But you don't
link the Windows kernel into your application, do you? It does some
weird magic with processor rings and code gates to enter kernel mode to
run the code.
I'm no expert, but as I say, I was under the impression that the usual
way to access a DLL is to link in a small C stub which defines the code
necessary to dynamically find and execute the exported functions from
the DLL.
>> Which is a bit like developing software for Linux and insisting that
>> everybody should avoid using Bash.
>
> Yep. More like developing distributed programs for Linux and deciding
> that sockets are too hard to use.
LOL! Yeah...
Seriously. Everybody talks about "hey, it's cool. Oh, except on Windows,
where we have to solve DLL Hell. But hey, who actually uses Windows?"
Personally, I thought "DLL hell" went away about 10 years ago...
>>>> I'm not seeing why you would need to do this with cold code update
>>>> either.
>>>> You only need to shut down the processes related to the thing you're
>>>> actually changing.
>>>
>>> Then you have a bunch of different processes on the same machine
>>> fighting over resources. Sending messages between them means you now
>>> have a bunch of context switches, etc.
>>
>> I don't follow.
>
> It's less efficient to have the kernel scheduler scheduling the
> different processes than to have the Erlang-specific scheduler doing it.
> That's why people make 100,000 erlang tasks in one process and doing the
> same in Linux will bring the kernel to its knees, if not run you out of
> memory.
Right. So all you're saying is that OS processes are heavier than Erlang
processes.
One thing Erlang can do (and Haskell can't, easily) is that because
Erlang is a VM, you can have several unrelated Erlang applications
running on the same VM. But to run multiple Haskell applications, you
would have to have multiple copies of the Haskell runtime in action.
Which, as you say, isn't something you want to do too much of.
>>> Yep. And that's why building a big system like this with static
>>> type-erased data is more difficult than dynamic tagged data.
>>
>> ...which is why the Haskell implementation is using dynamic tagged data.
>
> Yep. And that loses a lot of the benefits of the static typing right there.
*sigh* This old argument again.
Yes, the entire program is statically typed, but this one tiny part
where you have to do a simple runtime type check automatically
COMPLETELY DESTROYS EVERY SINGLE ADVANTAGE OF STATIC TYPING!
>> Can't handle it _yet_. They have concrete plans for how they would
>> implement it, they just haven't yet.
>
> Fair enough. I look forward to seeing what they come up with.
I look forward to seeing whether they ever finish it.
(I lose count of how many projects targeting Haskell at the GPU have
been started. The number of them which produced a production-grade end
product is zero.)
>> 1. Make no attempt to verify whether data structures match at all.
>
> Right.
>
> Actually, even worse, in Erlang, the likelihood is that you just leave
> the mismatched message in the buffer, which then grows until it crashes
> the whole machine with no obvious reason. One of the poorly thought-out
> designs there, methinks.
I'll say!
Basically you need to manually make sure you send a version number at
the start of your message exchange, or something like that, and make
sure that all servers and clients you write can handle all versions of
the protocol.
Or design the protocol so that it never needs to change. (Which is not
infeasible if you can send code as part of the protocol I suppose...)
>> (By contrast, Haskell might potentially be able to distinguish the old
>> type
>> and the new type at the type level, if the structure of the type has
>> actually changed, and issue a compile-time warning.)
>
> This assumes you know at compile time what types the other side is
> using, which also isn't always true. :-)
Not really. When you compile v1, you assume that the other side will be
v1 as well. When you compile v2, the compiler checks what you changed,
and warns you if you don't explicitly handle the v1 data (unless it's
identical).
>> 2. I have literally no idea how Erlang sends functions over the wire.
>
> It's out in the erldocs somewhere, but I can't find it after five
> minutes of looking around. They specify the wire format of everything,
> including that.
Yeah, I figured.
The Haskell implementation has a potential advantage in that you can
specify precisely how to serialise stuff if you want to. (Usually to
send a more compact representation by leaving off data which can be
recomputed at the other side, making use of the special structure of the
data to skip parts of it, etc.) Of course, the bit that tells the other
side who the message is for and what type it contains isn't open to
negotiation. ;-)
>> assumed it just sends the VM executable code over the wire.
>
> Given that I can write a function on an x86 machine and ship it over to
> a program running on a Sparc that has been running since before I bought
> the x86 machine, yah, I'd say there's some sort of virtual code being
> transfered. :-)
And yet, that would seem rather heavy compared to just sending a
function name (or rather, a *unique* function identifier), so perhaps
Erlang actually does it that way like Haskell is doing. Or maybe it only
sends the code if the other side doesn't already have it or something.
Come to think of it, I'm still figuring out how it manages to send atoms...
>> In both cases, it looks like you need a name plus some kind of version
>> number, or maybe a hash of a description or something, to distinguish
>> things
>> that the programmer has assigned identical names to...
>
> It depends on whether you're sending a function or the name of the
> function, really.
Well, we're sending type names too, which give you the same problem.
(And sending a type definition doesn't help, because we still need to
figure out whether they're *meant* to be the same type or not.)
Post a reply to this message
|
![](/i/fill.gif) |