|
![](/i/fill.gif) |
>> Suppose, for example, that I wanted to implement a lambda expression
>> interpreter.
>
> I don't think most java programmers would want that. :p
And I care because...? ;-)
> but kudos for installing and configuring netbeans just for that... :)
Well, not /just/ for that. It was the smallest example I could think of
off the top of my head. The /real/ application I'm trying to build would
take way longer to explain.
>> In reality, you /probably/ want to make it insert some brackets and
>> stuff
>
> you really can't spell parenthesis, huh? ;)
I really can't *pronounce* that out loud, no.
Besides, why use 7 syllables when 2 will do? ;-)
>> Now let's try the same thing in Java:
>> If your screen is anything like mine, that lot doesn't even fit on one
>> page. This is /a lot/ of code.
>
> Java is very obviously verbose, and it doesn't help when people even go
> further and write damn "public" all over in every occasion!
It's part of the language syntax. (Amusingly, you're not actually
/allowed/ to declare a class as private...)
> class Apply? Really? The name itself and the behaviour conveying an
> action shouldn't be best served as methods of Expression?
It denotes an expression where a function is applied to an argument.
It's part of the parse tree. It's data. That's what an object is
supposed to be: data.
Now, if this was an airline booking system, and somebody wrote a class
implementing the process of applying for a ticket, then, yuh, that's not
a sensible design. That's an action. Objects aren't supposed to be actions.
> Now try to write an object system in haskell.
That's not even hard. :-P
Functions are first-class, right? So you can create a "class" which is
simply a data structure that contains "methods" as fields with function
types. The result is something like JavaScript's notion of objects.
Or, if you don't want to do it that way, you can use Haskell's existing
type-class system to do it more naturally. Even mutable objects aren't
especially hard. And the module system easily gives you public and
private methods and fields.
Dynamic upcasts and downcasts are a bit more work. You can use
Data.Dynamic to implement that. And Haskell already has "generics" out
of the box. :-P Even multiple inheritance is no real problem. (Or at
least, implementing multiple interfaces. Actually /inheriting/ stuff
without implementing it more than once is mildly harder.)
In short, it's not hard to implement a weak language in a stronger one.
Try implementing a Pascal compiler in 1980s era BASIC. Good luck with
that. Now try implementing a BASIC interpreter in Pascal. Pretty easy,
isn't it?
>> Now suppose that, for some strange reason, I want to be able to check
>> whether two expressions are the same.
>> OK, so only 14 lines of actually new code. The hashCode() override is
>> not /strictly/ necessary, but the IDE whines like hell if you don't, and
>> it's highly likely that you're going to put variables as keys into a
>> HashMap at some point, in which case hashCode() had better work
>> correctly!
>>
>> In Haskell, you can simply say
>>
>> e `equals` f =
>> case (e, f) of
>> (Variable x, Variable y) -> x == y
>
> as far as I can tell, this is not the same code as the java one: you're
> not checking here if the variables have the same name too, only if they
> are instances of the same type.
Wrong.
"e" and "f" are lambda expressions. If they are both variables, then "x"
is the variable name of "e", and "y" is the variable name of "f". The
line "x == y" does what you'd imagine it does - i.e., it checks whether
the names are the same.
>> In Java, you have to check whether the argument is null. (Impossible in
>> Haskell.)
>
> it's about the same as checking for an empty list.
Except that, when you're not dealing with a list, then you never have to
worry about it being empty, do you? :-P
> BTW, that check could be at the base class in an ancestor method. But
> you wrote it as abstract for whatever reason...
I'm not even sure what that's supposed to mean.
>> You have to check whether the argument is of a comparable
>> class. (Haskell's static type checking does that for you at
>> compile-time. Actually Java's generics could do that too if they
>> extended it a teeny weeny bit... but they haven't.)
>
> I'm sorry, but if you wanted at least some type checking in java,
> shouldn't you do:
>
> public boolean equals(Expression obj)
>
> instead of
>
> public boolean equals(Object obj)
>
> ?
Unfortunately, Object.equals() is defined to take Object as a parameter,
not any more specific subclass. So, no, you can't do that.
(Or rather, you can, but now you're not overriding Object.equals(),
you're just creating a new, unrelated method of your own.)
> The compiler then would warn you whenever you passed something like
> exp.equals(2) (which, yes, reads kinda weird since a number literal like
> that should be an expression after all).
Have your forgotten? This is Java. 2 is not an object. Therefore it can
never be passed to something expecting Object.
>> Man, Java is a blunt knife! (But oh so hard to hurt
>> yourself with... yeah, right!)
>
> all in all, it read like object oriented code from a C programmer...
...which is ironic, given how hopeless I am at C. :-P
Seriously, I know how to write object-oriented code. I've been doing it
for years. I have certificates to prove it. I'm just saying, Java makes
everything /so/ much work, it takes forever to actually get anything done.
> now, I'm not a java programmer nor enjoy it. But people frequently enjoy
> making it sound actually worse than it is.
Right now I'm only talking about real, actual problems that I'm running
into right now as I try to write my code.
I almost feel like I should be writing a "compiler" that takes the
3-line version saying what data structure I want, and generates the
5-file 44-line monstrosity that the Java compiler expects. It would save
me a bunch of typing, and then I could go in and write the actual code
that turns it into more than just a dumb data structure...
Post a reply to this message
|
![](/i/fill.gif) |