![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 5/15/2011 3:22, Warp wrote:
> which was to properly handle C bitfields.
Given that C doesn't define what order bit fields go in, that seems like a
tall order. You can't technically do that from assembler, either. :-)
Otherwise, it would seem pretty easy to write Haskell code (or any other
language that handles integer math) to just use masks and multiplies and
divides.
--
Darren New, San Diego CA, USA (PST)
"Coding without comments is like
driving without turn signals."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 15/05/2011 05:41 PM, Darren New wrote:
> On 5/15/2011 3:22, Warp wrote:
>> which was to properly handle C bitfields.
>
> Given that C doesn't define what order bit fields go in, that seems like
> a tall order. You can't technically do that from assembler, either. :-)
>
> Otherwise, it would seem pretty easy to write Haskell code (or any other
> language that handles integer math) to just use masks and multiplies and
> divides.
There's a Haskell standard library that offers all the usual bit-level
operators, so it's not like you have to multiply by 2 when what you
really want is a left-shift.
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 15/05/2011 11:22 AM, Warp wrote:
> Orchid XP v8<voi### [at] dev null> wrote:
>> I'm fairly sure I posted one in the other group a while back. Heck, I
>> even got qsort() from stdlib.h to work arbitrary Haskell data types,
>> just because Warp said it wasn't possible.
>
> While calling C's qsort() from Haskell is impressive, you still failed
> to demonstrate the next challenge, which was to properly handle C bitfields.
I thought the next level was setjmp()?
> So there's still potentially something that Haskell cannot do with C... :P
If it's really that hard, ask C to do it, and call C from Haskell.
For that matter, C can't access [non-trivial] Haskell data either. If
your C program wants to, say, access the 7th element of a Haskell list,
it has to call Haskell and ask Haskell to fetch it and return something
simple enough for C to comprehend. (The 7th element might not *exist*
yet, for example...)
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> Argument from verbosity is seldom a good argument in programming.
>> Just because something is shorter doesn't necessarily mean it's better.
>
> I would say in this case it is, because all the extra stuff is just
> verbiage. It obscures the algorithm you're actually interested in, which
> is to make a new list where each element is the old list with 'bar'
> applied to it. All the stuff with the iterator and the types and all is
> just junk you have to repeat wherever you need to do this.
A far more relevant objection would be "how often does Haskell let you
do less work?"
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> foreign import stdcall "windows.h PostMessageW"
>> postMessage :: HWND -> WindowMessage -> WPARAM -> LPARAM -> IO LRESULT
>
> Oh yea. Very nice, yes. Amazing how many of the pre-C# languages made
> such a thing so tedious.
Hey, our language is *great*! Why would you ever want to call anything else?
>> How this actually finds the necessary code to execute, I have no idea.
>
> That's why they call it "the registry".
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.
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...
>> You cannot access Haskell data from C at all. You can access C data from
>> Haskell if you're careful.
>
> OK. That's what I figured. I couldn't imagine how C was getting to lazy
> data easily.
You *can* do it of course, but it'll probably break with the next
release of the compiler, so nobody does it. Instead, you write Haskell
stub functions to fetch whatever item of data you want, and call that
from C. (Or just design the program the other way around.)
I'm unsure how much runtime overhead is involved in calling between C
and Haskell.
>> You can also build Haskell DLLs. I have no idea how that works...
>>
>> Speaking of which, GHC now supports compiling each Haskell library as
>> a DLL,
>> rather than linking them all statically. Unfortunately, this is broken
>> out-of-the-box. If you compile this way, you have to manually find all
>> the
>> DLLs your program requires and move them into the search path, because
>> the
>> GHC installer doesn't do this for you. Oops!
>
> That's why they call it the registry. :-)
The general opinion among Haskell developers is that Windows is "that
evil platform that we shouldn't have to support". In particular, DLLs
and the registry are both regarded as being impossibly complex to use,
and to be avoided to the maximum extent possible.
Which is a bit like developing software for Linux and insisting that
everybody should avoid using Bash.
>> Wouldn't converting one gigabyte of data to a new format online take
>> just as long as reloading it from disk?
>
> And yes, it would take just as long, but you don't have to do it all at
> once. You can be servicing requests, and reformatting data while you're
> not servicing requests.
OK, fair enough.
>> 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.
>>> You can also convert things slowly, using the old data in the new code
>>> until all the old code is gone, then slowly work thru the data (perhaps
>>> updating it each time it's touched) to the new format.
>>
>> This is an unavoidable requirement which *must* be met if you want
>> distributed processing. Otherwise upgrading the system requires
>> stopping the
>> entire distributed network.
>
> 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.
>> No, this is the fundamental problem with a small proof-of-concept
>> implementation exploring whether it's even slightly possible to do this.
>> Obviously the current implementation does not yet provide everything
>> necessary for production use. Nobody is claiming it does.
>
> Sure. I'm just not sure they've proved the concept if they can't handle
> that. :-)
Can't handle it _yet_. They have concrete plans for how they would
implement it, they just haven't yet.
>> What is needed - and the documentation makes plain that the
>> implementors are
>> quite aware of this - is some way of varifying that the identifiers
>> you send
>> actually refer to the same thing. I don't actually know how Erlang
>> manages
>> to do this;
>
> Dynamic typing. :-)
That's not an answer. Haskell is typing values sent over the wire
dynamically too. That doesn't automatically solve the problem.
There are two things to check: data structure type names and function
names. The Erlang answer seems to be:
1. Make no attempt to verify whether data structures match at all. If
the old code excepts data in one format and the new version expects data
in an almost identical yet slightly different format, when the new code
fires up it will just crash due to the data mismatch. Unless you
specifically tested for this and wrote lots of code to make it work.
(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.)
2. I have literally no idea how Erlang sends functions over the wire. I
had assumed it just sends the VM executable code over the wire.
Obviously that only works if you're running on a VM. Haskell isn't.
(There *is* a VM, but it's fairly slow, and has various other gotchas.)
Haskell is sending the function name over the wire, but that only works
if the name means the same thing at the other end.
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...
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
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.
> 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.
> the compiler, so nobody does it. Instead, you write Haskell stub functions
Yep. Kind of like calling C++ from C.
> 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.
>>> 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.
>> 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.
> 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.
> 1. Make no attempt to verify whether data structures match at all. If the
> old code excepts data in one format and the new version expects data in an
> almost identical yet slightly different format, when the new code fires up
> it will just crash due to the data mismatch. Unless you specifically tested
> for this and wrote lots of code to make it work.
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.
> (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. :-)
> 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.
> 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. :-)
> 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.
--
Darren New, San Diego CA, USA (PST)
"Coding without comments is like
driving without turn signals."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/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) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 5/17/2011 1:07, Invisible wrote:
>> 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.
Right. It's probably in the C runtime.
> 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.
Right. Unless you register it. Then the linker looks up the code in the
registry and links it against the file that the registry says the code is
in. That's what the registry is for, and why it's called a registry.
You may need to make it a COM DLL first to register it; I don't remember the
exact details any more.
> (The answer is probably something like "GHC automatically includes the Win32
> files at link time".)
That's my guess.
> 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.
In every system I've ever used, the "weird magic" is in a linker file that
always gets loaded. For example, msvcrt.dll (Microsoft visual C run time)
for Windows, glib for GCC under Linux, etc.
> 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.
Or branch to a jump table that the loader fills in with addresses from the
DLL when it loads the DLL, which it loads based on the headers of the program.
Most systems do almost all of this automatically specifically because C
doesn't have any standard syntax for doing this. I suspect if
dynamically-loaded code was the norm in C from the beginning, much less
would be automated by the OS's loader.
> Personally, I thought "DLL hell" went away about 10 years ago...
Yes, pretty much.
> Right. So all you're saying is that OS processes are heavier than Erlang
> processes.
Well, much heavier than Linux or Windows processes. By many, many orders of
magnitude. There are OSes where processes are very light, like Singularity,
Mach, AmigaOS, etc. Generally what you hear referred to as a "microkernel"
is a kernel where processes are so lightweight that you can afford to put
each device driver and file system in its own process.
> 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.
Yes. Indeed, the whole point of the VM is to be a virtual machine, so the
idea of an "application" is a user-level construct, not something built into
the language. (In much the same way that a "login" is a user-level
construct in UNIX/Linux, whereas in most other OSes, it's an OS-level
construct.)
> 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!
I didn't say that. I said it loses a lot of the benefits, where "benefits"
are "guarantees" in my mind.
Now, in this particular case, it probably is doing enough work in the
connected set of processes that converting from dynamic to static typing is
worthwhile. In the discussions we were having before, I was talking about
things like web pages, that almost never do any significant processing on
their own at the server, so statically typing a web page where you're
translating dynamically typed SQL results into HTML doesn't really help to
have static typing. I.e., when it's not one tiny part but rather a majority
of the program, it's worse.
> 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 you just check the types and do the right thing with them. Of course,
knowing what the right thing is can be difficult. E.g., if you have been
working with 2D longitude/latitude, and the new version needs altitude also,
you could have all the places that take a 2-element tuple start also working
with a 3-element tuple and asking how many elements it has, then start
generating 3-element tuples. The number of elements in the tuple can serve
as your version number.
> 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...)
Well, they handle it by letting you upgrade the code.
> 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).
That's fair. It would be interesting to see how that's specified.
> The Haskell implementation has a potential advantage in that you can specify
> precisely how to serialise stuff if you want to.
You just do that in code with Erlang. I.e., you write your own serializer,
or you send a message to a local agent that then sends the message to the
remote agent that has only what you want.
> And yet, that would seem rather heavy compared to just sending a function
> name (or rather, a *unique* function identifier),
Not all functions have names. For the functions that have names, I believe
you just send the fully-qualified name of the function. (And since function
names are atoms, the actual text of the function name is cached after the
first time, so you don't have to send more than "the 37'th function I've
sent you" next time.)
If you send a lambda, I believe it sends the bytecode. There may be caching
involved there too, but I don't remember.
I was too awed by the landmines in the data format to remember the other
details.
> Come to think of it, I'm still figuring out how it manages to send atoms...
It sends them as text, the first time.
--
Darren New, San Diego CA, USA (PST)
"Coding without comments is like
driving without turn signals."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
More erlang fanning:
The protocol between the deamons:
http://www.erlang.org/doc/apps/erts/erl_dist_protocol.html
The protocol between the individual actors:
http://www.erlang.org/doc/apps/erts/erl_ext_dist.html
You want to look at 8.21 and 8.22. It seems the code doesn't ship, since
logically the function can't really be constructed at runtime. Instead, it's
a reference into the BEAM file (where a BEAM is like a java jar).
Because of course "external term format" is exactly what anyone would google
for to find that. I'm also rather amused that altho Erlang has wonderfully
powerful expressions for parsing byte streams, they used ASCII art with
ambiguous textual descriptions to describe the format of the stuff on the
wire instead of giving you the Erlang expression that would parse it
unambiguously.
--
Darren New, San Diego CA, USA (PST)
"Coding without comments is like
driving without turn signals."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> 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.
>
> Right. Unless you register it. Then the linker looks up the code in the
> registry and links it against the file that the registry says the code
> is in. That's what the registry is for, and why it's called a registry.
>
> You may need to make it a COM DLL first to register it; I don't remember
> the exact details any more.
I was under the impression that the registry is *only* for dynamic
linking, and has nothing to do with static linking [which is what I'm
talking about here].
> In every system I've ever used, the "weird magic" is in a linker file
> that always gets loaded. For example, msvcrt.dll (Microsoft visual C run
> time) for Windows, glib for GCC under Linux, etc.
Right. That's probably it...
> Most systems do almost all of this automatically specifically because C
> doesn't have any standard syntax for doing this. I suspect if
> dynamically-loaded code was the norm in C from the beginning, much less
> would be automated by the OS's loader.
On the other hand, the main advantage of C is that almost nothing is
built-in, which means that everything can be changed... ;-)
>> Personally, I thought "DLL hell" went away about 10 years ago...
>
> Yes, pretty much.
This is from the people who actually had to ask "does Windows actually
support letting multiple processes open the same disk file at once?"
>> 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.
>
> Yes. Indeed, the whole point of the VM is to be a virtual machine, so
> the idea of an "application" is a user-level construct, not something
> built into the language.
Fair enough.
Question: Does that mean that one process can produce so much garbage
that it forces endless GC cycles, slowing other unrelated processes
down? Or does the VM partition memory on a per-process basis or something?
>> 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!
>
> I didn't say that. I said it loses a lot of the benefits, where
> "benefits" are "guarantees" in my mind.
>
> Now, in this particular case, it probably is doing enough work in the
> connected set of processes that converting from dynamic to static typing
> is worthwhile. In the discussions we were having before, I was talking
> about things like web pages, that almost never do any significant
> processing on their own at the server, so statically typing a web page
> where you're translating dynamically typed SQL results into HTML doesn't
> really help to have static typing. I.e., when it's not one tiny part but
> rather a majority of the program, it's worse.
>
>> 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 you just check the types and do the right thing with them.
Well yeah, but if you're trying to use a mere textual "name" to decide
what type something is, you need a version number or something to go
with the name, to make it unique.
What Erlang is doing is considering any two types to be "identical" if
they have the same *structure*. That wouldn't do for Haskell; consider,
for example, how a PortID and a ThreadID are both 32-bit signed
integers, but are considered utterly different, incompatible types.
[Of course, TRWTF is that it's *signed*...]
>> 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...)
>
> Well, they handle it by letting you upgrade the code.
You can upgrade the code, but unless you upgrade it all at once, both
versions need to speak the same wire protocol.
>> 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).
>
> That's fair. It would be interesting to see how that's specified.
I guess we sit back and see if they ever release anything...
>> The Haskell implementation has a potential advantage in that you can
>> specify
>> precisely how to serialise stuff if you want to.
>
> You just do that in code with Erlang. I.e., you write your own
> serializer, or you send a message to a local agent that then sends the
> message to the remote agent that has only what you want.
Yeah, I guess that works too.
Presumably Erlang allows you to serialise cyclic data structures, which
is notoriously hard for a pure functional language.
>> And yet, that would seem rather heavy compared to just sending a function
>> name (or rather, a *unique* function identifier),
>
> Not all functions have names. For the functions that have names, I
> believe you just send the fully-qualified name of the function.
Only works if foo/3 on node X is the same thing as foo/3 on node Y. ;-)
> If you send a lambda, I believe it sends the bytecode. There may be
> caching involved there too, but I don't remember.
>
> I was too awed by the landmines in the data format to remember the other
> details.
I'll have to check it out sometime...
>> Come to think of it, I'm still figuring out how it manages to send
>> atoms...
>
> It sends them as text, the first time.
Oh, right. So atoms are *globally* unique, not unique to each node?
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |