![](/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 8/20/2012 1:31, Invisible wrote:
> You said C# lets you call arbitrary machine code as easily as calling
> another C# function. I said it doesn't.
Assuming it uses one of the calling conventions that C# understands, then
yes, it does.
> You cannot pass arbitrary Haskell expressions to C. You can only pass
> primitive data types that C understands. (Things like int or long or void*.)
> If C needs to access Haskell stuff, you write Haskell functions that inspect
> the Haskell stuff and return something that C understands, and then have C
> call that.
So it's hard to call across the boundaries there.
>> And of course
>> if the C isn't actually a function in the functional sense, I'm not sure
>> how Haskell handles it.
>
> If the code you're trying to call has no observable side effects (e.g.,
> sinh() or something) then you mark it as a pure function. If it /does/ have
> observable side-effects, then you mark it as an I/O action, and handle it
> the same way as any other I/O action. Really, it's not hard.
OK, cool.
>> For example, it's really not obvious how easy it
>> would be to invoke a C function that takes as one of its arguments a
>> pointer to a function.
>
> Do you remember that time I used the C sort() function to work a Haskell
> data structure? Do you remember how I don't even know all that much about C,
> and yet it only took me about 20 minutes to figure it out?
>
> Seriously, it's not "trivial". But it's pretty damned simple.
OK. Again, note that I didn't say it's not easy. I said it's not obvious to
me how easy it is. I don't know Haskell very well, remember?
>>> JavaScript is a language invented for controlling web browsers. I
>>> don't know of anything else that runs it.
>>
>> There are lots of other applications that have incorporated javascript.
>
> Really?
I gave you a wikipedia link to a giant list, even! :-)
> Haskell is statically typed. But there's a library for doing stuff with
> dynamic types. Basically, it lets you convert any suitable value to a
> special "Dynamic" type. You can then later try to cast it back to something
> else, which succeeds iff that is actually the correct type. You know, the
> usual deal.
OK. Still a bit clunkier than C#. :-)
> At worst, if you wanted to talk to something dynamic, you could just mark
> every single thing it touches is "type unknown" until you try to do
> something with it. It isn't that hard.
It sounds more clunky than difficult.
--
Darren New, San Diego CA, USA (PST)
"Oh no! We're out of code juice!"
"Don't panic. There's beans and filters
in the cabinet."
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 8/20/2012 4:02, Invisible wrote:
> Object-oriented programming was supposed to make everything polymorphic and
> wonderful.
Uh, no.
> But then they discovered the container problem, so they invented
> generics.
The container problem you describe is only a problem for statically typed
languages.
> they decided that having eight-billion interfaces like "Runnable",
> "ScrollEventListener", "DragEventListener", "CheckBoxEventListener" and so
> on was just stupid.
It was always stupid, and most languages don't need that.
> So Eiffel invented "agents", C# invented "delegates",
> and Java offered the "reflection API"; all of them different attempts to
> solve the same language design problem.
The reflection API has nothing to do with delegates or agents. Indeed, C#
has a reflection API also.
> This is the kind of stuff I'm talking about. All these different languages,
> all with lots and lots of "features" for trying to solve stuff. And then
> there's Haskell, which consists of just 6 constructs in the entire language,
> and solves all of it.
And Smalltalk, which also solves all of it with the same level of
constructs. But the stuff you're complaining about in C# isn't the core
language either. Threads and the reflection API aren't part of the "core
language" of C# either.
--
Darren New, San Diego CA, USA (PST)
"Oh no! We're out of code juice!"
"Don't panic. There's beans and filters
in the cabinet."
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 8/20/2012 7:34, Invisible wrote:
> And this is bad somehow?
Yes. Quite a bit.
--
Darren New, San Diego CA, USA (PST)
"Oh no! We're out of code juice!"
"Don't panic. There's beans and filters
in the cabinet."
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 8/20/2012 1:25, Invisible wrote:
> On 19/08/2012 05:08 PM, Darren New wrote:
>> On 8/19/2012 3:13, Orchid Win7 v1 wrote:
>>>>> You wouldn't be able to do this for arbitrary code.
>>>>
>>>> And that's what I'm talking about. If you want your program to run 15
>>>> years without ever stopping, you pretty much need to be able to replace
>>>> arbitrary bits of code, including type signatures, while you're running.
>>>
>>> And if this was a problem for your application, you would write it in
>>> such a way as to facilitate doing this.
>>
>> Except it's exponentially harder if your language doesn't support it.
>
> No, it isn't.
>
> It's exponentially harder IF YOUR LANGUAGE SUCKS. If you have a powerful
> language, then adding new things is quite easy.
OK, show me a Haskell library that lets me replace any function of the
language with a new version of that function, keeping the old function for
any lazy values that might refer to it, until all those lazy values have
turned strict.
Can you write a Haskell function that wraps every other Haskell function
declared? Maybe. I know a few languages like that. But it still doesn't
make adding that feature easy.
> Well, no, that should be quite easy: You have a rule that inside a
> transaction, you don't try to do anything observable to the outside world.
> If you do, it won't work, and it will be your fault. Problem solved.
Except that makes it useful for the areas in which C# is used, namely
calling library code. You can't know if the code you're calling does
something observable. That's the point.
> The trouble is, they tried to make it so that any arbitrary code can be run
> in a transaction. That's impossible. Which is why it didn't work.
Right. More to the point, they tried to make it so you could use arbitrary
library code for which you don't have the source inside a transaction.
> You might say "but almost all C# code would be disqualified!" But remember,
> the purpose of a transaction is /only/ to coordinate threads. You don't run
> the entire application inside STM, just the tiny bits related to
> synchronisation.
Right. But say the bit you want to synchronize is implemented in someone's
library, and they log a message when something fails.
>> The point I'm making is that
>> many of the decisions in Erlang were made to support this sort of
>> long-running self-healing software. Yes, you could do the same thing in
>> Haskell, but then it would look like Erlang.
>
> Would it, now?
>
> Adding features for distributed concurrency and hot code replacement would
> make Haskell have crap syntax and weak typing?
Well, I think "crap syntax" is debatable, but I'm tending to agree with you.
Weak typing? Most certainly.
> You're aware of the prior art on this subject, I assume? You know about the
> project where they managed to actually implement typed message sending and
> remote code execution? Transparently? Without altering the Haskell language
> at all, just the compiler?
That's not the main part of Erlang. You're talking about Erlang as if we
were talking about SQL and one of us is focusing on the fact that it's also
a functional language. That's not the point.
The fact that Erlang has remote code execution and sends messages is a
*result* of the Erlang design goals, not a fundamental property. (For
example, Hermes has the same design goals, and it doesn't support remote
execution in the language either.)
> Being able to implement something is one thing. Being able to implement it
> /easily/ is another. And that's the goal of designing a good language: to
> make stuff easy.
You keep asserting that it's easier in Haskell to do some of these things
than it is in Erlang or C#. But you've yet to actually provide any evidence
of this beyond vigorous assertions.
--
Darren New, San Diego CA, USA (PST)
"Oh no! We're out of code juice!"
"Don't panic. There's beans and filters
in the cabinet."
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 26/08/2012 04:30 AM, Darren New wrote:
> On 8/20/2012 1:31, Invisible wrote:
>> You said C# lets you call arbitrary machine code as easily as calling
>> another C# function. I said it doesn't.
>
> Assuming it uses one of the calling conventions that C# understands,
> then yes, it does.
And if some machine code has the same calling convention as Haskell,
then it's trivial to call. Admittedly, no such code exists anywhere,
because the Haskell calling convention is insanely complicated and
changes every few years, but you see my point. :-P
>> You cannot pass arbitrary Haskell expressions to C. You can only pass
>> primitive data types that C understands. (Things like int or long or
>> void*.)
>> If C needs to access Haskell stuff, you write Haskell functions that
>> inspect
>> the Haskell stuff and return something that C understands, and then
>> have C
>> call that.
>
> So it's hard to call across the boundaries there.
Not so much "hard" as "non-trivial".
>>> And of course
>>> if the C isn't actually a function in the functional sense, I'm not sure
>>> how Haskell handles it.
>>
>> If the code you're trying to call has no observable side effects (e.g.,
>> sinh() or something) then you mark it as a pure function. If it /does/
>> have
>> observable side-effects, then you mark it as an I/O action, and handle it
>> the same way as any other I/O action. Really, it's not hard.
>
> OK, cool.
Three guesses how I/O actions are "really" implemented. ;-)
>> Haskell is statically typed. But there's a library for doing stuff with
>> dynamic types. Basically, it lets you convert any suitable value to a
>> special "Dynamic" type. You can then later try to cast it back to
>> something
>> else, which succeeds iff that is actually the correct type. You know, the
>> usual deal.
>
> OK. Still a bit clunkier than C#. :-)
What? C# doesn't ask you to write explicit upcasts and downcasts sometimes?
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) |
> You keep asserting that it's easier in Haskell to do some of these
> things than it is in Erlang or C#. But you've yet to actually provide
> any evidence of this beyond vigorous assertions.
And you keep asserting that Haskell is a bad language, without much
evidence either. :-P
Erlang is /obviously/ much better at hot code swapping than Haskell
currently is. This is not in debate. But you keep asserting that Haskell
/can never/ be as good as Erlang. Because it's somehow /impossible/ for
somebody to come up with a Haskell implementation that does what Erlang
does. You still haven't explained why that is.
Likewise, C#.Net gives you access to the entire .Net platform library.
This has vastly more functionality than what's available for Haskell.
This is because C# is MORE POPULAR than Haskell, and NOT because Haskell
is badly designed.
My argument was never about how much external stuff is available for
Haskell. My argument was that Haskell is a clean, simple language that
manages to solve the same problems that other languages can only solve
using a vast swathe of complicated "features" hard-wired into the language.
C# has methods and inheritance and subtype polymorphism and dynamic
dispatch and delegates and lambda abstractions and broken multiple
inheritance and reflection and... Haskell just has first-class
functions. Solves all of the above, with a fraction of the complexity.
It's simpler to explain, it's simpler to use, it's simpler to read.
That's what I'm talking about.
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 8/26/2012 1:01, Orchid Win7 v1 wrote:
> On 26/08/2012 04:30 AM, Darren New wrote:
>> On 8/20/2012 1:31, Invisible wrote:
>>> You said C# lets you call arbitrary machine code as easily as calling
>>> another C# function. I said it doesn't.
>>
>> Assuming it uses one of the calling conventions that C# understands,
>> then yes, it does.
>
> And if some machine code has the same calling convention as Haskell, then
> it's trivial to call. Admittedly, no such code exists anywhere, because the
> Haskell calling convention is insanely complicated and changes every few
> years, but you see my point. :-P
I see your point. But you seem to be missing mine.
>
>>> You cannot pass arbitrary Haskell expressions to C. You can only pass
>>> primitive data types that C understands. (Things like int or long or
>>> void*.)
>>> If C needs to access Haskell stuff, you write Haskell functions that
>>> inspect
>>> the Haskell stuff and return something that C understands, and then
>>> have C
>>> call that.
>>
>> So it's hard to call across the boundaries there.
>
> Not so much "hard" as "non-trivial".
Well, yes. You have to restructure your Haskell code and basically re-write
it in C style in order to call it from C.
>>> Haskell is statically typed. But there's a library for doing stuff with
>>> dynamic types. Basically, it lets you convert any suitable value to a
>>> special "Dynamic" type. You can then later try to cast it back to
>>> something
>>> else, which succeeds iff that is actually the correct type. You know, the
>>> usual deal.
>>
>> OK. Still a bit clunkier than C#. :-)
>
> What? C# doesn't ask you to write explicit upcasts and downcasts sometimes?
Not for dynamic variables. And almost never for regular C# values either.
--
Darren New, San Diego CA, USA (PST)
"Oh no! We're out of code juice!"
"Don't panic. There's beans and filters
in the cabinet."
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 8/26/2012 1:51, Orchid Win7 v1 wrote:
>> You keep asserting that it's easier in Haskell to do some of these
>> things than it is in Erlang or C#. But you've yet to actually provide
>> any evidence of this beyond vigorous assertions.
>
> And you keep asserting that Haskell is a bad language, without much evidence
> either. :-P
No I didn't. I simply said a tiny elegant language where you can do
everything in libraries is usually not superior to a language designed for
the kind of coding you're doing.
> Erlang is /obviously/ much better at hot code swapping than Haskell
> currently is. This is not in debate. But you keep asserting that Haskell
> /can never/ be as good as Erlang.
It can't be as good at Erlang as what's built into Erlang. OK, granted,
Erlang may not be the best example, because it's a hacky kludge of a
language, but you know what I mean. Were Erlang not based on an interpreter
written in Prolog, taking the same concepts and building them into a
language (like Hermes or NIL perhaps) instead of having them as libraries is
superior.
> Because it's somehow /impossible/ for
> somebody to come up with a Haskell implementation that does what Erlang
> does. You still haven't explained why that is.
Because when you write a library, you get inefficiencies, you get different
people using different libraries, you get non-portability, and you get weird
type sorts of things, and incompatibilities between libraries. No, really.
That's what happens. I used to be a big fan of these very meta languages
(and I still am), but it turns out that once they're too meta, every program
takes tremendously more study to understand and modify.
There's a reason that LISP, Tcl, and FORTH didn't really take off any more
than Haskell did.
> Likewise, C#.Net gives you access to the entire .Net platform library. This
> has vastly more functionality than what's available for Haskell. This is
> because C# is MORE POPULAR than Haskell, and NOT because Haskell is badly
> designed.
No. It's because C# and .NET are *explicitly designed* to provide access to
vast libraries.
> My argument was never about how much external stuff is available for
> Haskell. My argument was that Haskell is a clean, simple language that
> manages to solve the same problems that other languages can only solve using
> a vast swathe of complicated "features" hard-wired into the language.
> C# has methods and inheritance and subtype polymorphism and dynamic dispatch
> and delegates and lambda abstractions and broken multiple inheritance and
> reflection and... Haskell just has first-class functions. Solves all of the
> above, with a fraction of the complexity. It's simpler to explain, it's
> simpler to use, it's simpler to read. That's what I'm talking about.
And the problem comes when you look at the use of a first class function and
try to figure out what is happening with it. And methods, inheritance,
subtype polymorphism, and dynamic dispatch are all the same thing. Delegates
and lambda abstractions are all the same thing. So you're listing a whole
bunch of ideas that let you express exactly what you mean precisely, and say
"but they're all subsumed by this really general mechanism."
Basically, you're saying "we could use a very simple and straight-forward
Haskell language, and replace methods and inheritance and subtype
polymorphism and ... and access to vast libraries with libraries that take
functions as function. But then those libraries would not only be as
complicated as the features you're decrying(*), but they'd also vary from
program to program. You'd never know whether the library you're using has
the same semantics, because it's not part of the standard and just a library.
(*) Yes, they would be, because a specific functionality built into the
compiler and language are going to be simpler than a hand-crafted library in
source code trying to provide the same functionality on top of a generic base.
It would be like driving a car with a mouse and keyboard. There's a reason
that all those "features" are there, and that reason is that they let you
say what you mean, instead of building a structure that says what you mean.
Why do we have while loops, for loops, recursion, if statements, case
statements, if then elseif and else, when all we really need is an if and a
goto?
--
Darren New, San Diego CA, USA (PST)
"Oh no! We're out of code juice!"
"Don't panic. There's beans and filters
in the cabinet."
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 26/08/2012 05:45 PM, Darren New wrote:
> (*) Yes, they would be, because a specific functionality built into the
> compiler and language are going to be simpler than a hand-crafted
> library in source code trying to provide the same functionality on top
> of a generic base.
This is really the central thing I disagree with.
STM is implementable as an external 3rd party library. (I have
personally done this.) And yet, it works beautifully.
Just because something isn't hard-wired, doesn't mean it has to work
badly or be hard to use.
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) |
Darren New <dne### [at] san rr com> wrote:
> On 8/20/2012 4:02, Invisible wrote:
> > Object-oriented programming was supposed to make everything polymorphic and
> > wonderful.
> Uh, no.
What do you mean? Isn't *everything* in a pure OO language an object (that
can be inherited from and specialized)?
> > But then they discovered the container problem, so they invented
> > generics.
> The container problem you describe is only a problem for statically typed
> languages.
I'm not sure the problem is any better in dynamically typed languages.
In a statically typed language you get an error at compile time if you
try to put an object of the wrong type in a container. In a dynamically
typed language you get an error at runtime when you try to use it. Is this
really "better"? I wouldn't say so.
> > This is the kind of stuff I'm talking about. All these different languages,
> > all with lots and lots of "features" for trying to solve stuff. And then
> > there's Haskell, which consists of just 6 constructs in the entire language,
> > and solves all of it.
> And Smalltalk
Don't forget Lisp.
--
- Warp
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) |