Re: The Language I want
- From: "Aaron Gray" <ang.usenet@xxxxxxxxx>
- Date: Mon, 9 Mar 2009 16:00:09 -0000
"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> wrote in message
news:l939z9ya7zrc.1nx816b6rzm1m$.dlg@xxxxxxxxxxxxx
On Sun, 8 Mar 2009 19:32:19 -0000, Aaron Gray wrote:
"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> wrote in message
news:z9uxovo1m6pj.1urlzkw2mvy1c.dlg@xxxxxxxxxxxxx
No. Visibility is an independent to type issue. It is a property of a
package / module. It has nothing to do with inheritance. So public and
private views only.
no protected members ? Why not ?
Because it is an artefact of C++ design fault which conflates classes
and
modules. If you don't then public and private suffice.
I disagree, protected allows you to call or modify methods of your parent
but not to allow using classes to access those protected members. This is
very useful for controlled encapsulation.
If you still disagree could you make your point clearer as I not sure I
understand what you are getting at ?
The point is that visibility belongs to package / module. It is not the
business of a type declaration. The package may declare several types
related in their implementation. So the package body would provide
visibility to the implementation of the type A to one the type B, provide
completely hidden operations and data shared by them etc.
I disagree, classes can hide implementation details from other classes (or
from outside) in the same namespace, module or package.
Why ever not, give me a good reason....okay
This all is extremely painful in the model you describe:
1. You need awful "friend class"
2. "friend" still does not work, when you add new classes
Okay, nothing wrong with friends, but you should possibly be able to declare
them the other way round too.
I see you point though.
3. You need static methods. With packages you just put things you need
into
the package.
Okay, nothing wrong with static methods, if they belong with the class they
should be in the class, not in the enclosing package. I can see what you are
getting at.
4. You need singletons when the module requires elaboration.
Explain.
5. This still does not work if you need to elaborate several types, their
data etc. C++ has massive problems with the elaboration order. With
packages you have a clear control upon what depends on what, and in which
order static things come into life.
Explain thurther.
6. Same applies to finalization.
Explain.
We need to debate this thurther.
No. Constructor / destructor aren't functions. There should be
built-in
constructors / destructors with user defined hooks of *properly* typed
subprograms.
They are static functions with special prominence.
No, they are not since you cannot specify their profile staying typed.
Constructor takes "no type" and converts it into "type T," this i
fundamentally inconsistent with the notion of strong typing.
BTW, under static function I understand "compile time function," and not
C++ kludge.
No I still define 'static' as C++'s static in my model.
These "class constructors and distructors" are one off functions called
when
a class is "loaded" or "unloaded" ie when it comes into being or dies,
this
allows static data members to be dynamically initialized.
They are not functions because, as I said, you cannot provide a signature
for. Consider a type T. Now what is the signature of a default constructor
of T, if it were a function or procedure? What would happen if somebody
calls this thing? Once, twice etc. You have to put a lot of words around
this "function," explaining why it behaves not in a way one would expect
from a normal function. If something does not behave as a function, then
it
is not one.
They are just special functions if you try to use them out of turn then you
will get a compiler warning or error message depending upon flags.
- most things/'units' can exhibit inheritance, for example
modules can inherit other modules so extending them.
First-class modules? That's difficult to make working. I doubt if it
can
work.
Dont see any problems with first class modules, can you please list
some.
How are you going to check types of the objects declared in dynamically
created module object?
Because everything is static, when a textual module is first loaded it is
compiled into a dll then loaded.
That is for sure, but what is static for the clients of the module? If you
treat a module as a first-class thing, then I would expect to be able to
do
things like a function that returns a module. Is it allowed?
You can certainly do this and reflect upon it.
Now consider
some context where I call this function, obtain a module and then call a
function from that module. Where I get the types of the function
parameters? They come from the module. How can I statically check them?
No this is all done dynamically with reflection.
I suppose you mean a much weaker thing than "truly" first-class modules.
What you mean is rather a sort of late binding.
I had considered making first class stuff workable AST's theat can be
modified and manipulated at run time with an interpreter that can run them,
but this would require a hole separate new runtime execution machine
archetecture. And thats alot of doubling up on things.
It is not that I am against it. For distributed systems first-class
modules
are of paramount importance. I just do not know how to reconcile things
without falling into self-interpreting programs and other "dynamic" havoc.
- generics/parameterized polymorphism
No generics. Constrained types instead.
Why ?
Generics is a huge mess.
Real generics, ie not C++'s generics are great they allow very efficient
good code to be generated particularly when combined with inline
functions/methods, saving lots of (physical) typing effort.
They are:
1. Unmaintainable
I agtre with this for older C++ templates, as error messages are crap, but
C++0x and concepts do alot to change this.
2. Unreadable
Depend on the code, some is some is overly cryptic.
3. Non-testable (you can test only instances, not the generics themselves)
Most of the time this is not a problem.
4. Hugely inefficient (templates cannot be shared)
Generacism can be shared in some instances.
5. Impossible to build anything bigger than boy examples. Consider 100K
source lines of generic code + one compiler error message. The objective:
understand the message, fix the problem
Yes, I have found this with C++, again 0x helps alot more.
6. No compiler can implement more or less elaborated generic framework.
This problem is known for C++ and for Ada compilers. I saw no one which
would not have severe bugs in the implementation of generics. It just does
not work, they fix one bug and introduce another
?
7. As for typing efforts, generics lead to a geometric explosion of the
source code. Yes, I mean the source code, not the expanded one. This
happens because generic language is very low level and lacks all important
abstractions. C++ templates are untyped, have no subprograms etc. Add here
that this is static, so "once generic, always generics." In the result the
programmer is forced to program in a language which abstraction level is
about of FORTRAN-IV or lower. No wonder that he would cut and paste
generics as hell.
This is not a problem with bounded generic parameters which is what I am
looking at.
8. Reuse is minimal
Consider C++'s 'vector<T>' I diagree, STL is well used, its not great but is
very prevalent.
9. Refactoring is almost impossible
I disagree.
So you don't like generics ;)
[I have an extensive experience with using generics in large projects.
That
is the reason why I hate them so much and nobody can convince me in
opposite. We have to agree to disagree.]
If generics is over used or badly used in a convuluted way I agree with you.
I would really like to learn some lessons from this.
If generics is used in place of templating then it is just crap
unmaintainable code you get.
By separating generics from templating I think this half the problem. And
not allowing unrestricted parameterization, when generic parameters are
qualified, quarters the problem again. And really helps the compiler do a
better and easier job too.
Although I was considering allowing the 'any' class to be used to qualify
generic parameters, but this would mean either back to parsing templates and
type checking them later when instatantiating them which is back to C++
territory. Or not allowing any usage of any apart from being passed through
to say a template. Not sure have not worked this one through fully.
They are sort of
oposite to polymorphism in a way.
They are polymorphism, called "parametric" and sometimes "static."
Yes they are static polymorphism :)
Templates are not C++ templates. With C++ the templates object signature
ie
its mangled name in assembler contains all the templates instantiated
parameter types. My generics would too. But my templates do not.
So you claim it is not a mess? (:-)
Combining templates with generics in the C++ model is a mess and can tend to
messy unreadable code particularly if you are resting your code on the fact
that it is Turin computable and I can do anything !;)
Also the compiler should be able to decide how to implement things,
virtual
or non virtual, or inlined, given the context such as generic parameters
if
there are any, and small world syndrome / whole program optimization
should
allow the right decisions to be made.
I would like a nonvirtual keyword then :)
You don't need any word because the type is different. When classes and
types are distinct, the type of the class is not the type of the class'
root type. So
f : T (specific for T, dispatches on the class T)
f : class T (specific for class T, i.e. it does not dispatch on it)
I like that, done from outside.
My new model is classes have virtual methods by default, they are
overridable though with a better key word than 'nonvirtual'
structs have non virtual methods by default, and may not even allow virtual
methods, I am not sure yet though.
You probably mean the interface of a compilation unit and its
separation
from the implementation. Everything visible in the declarative part of
a
unit is, well, visible.
Unless it is marked private, protected.
When private then invisible. Protected has no meaning.
Yes it does it protects members from access by users, but allows access
from
sub classes.
Subclass implementation is a user as any other. It is an important point
if
you want to encapsulate properly. Only children of the package should have
access, independently on whether they derive or not. Consider adding new
functionality on the class level. Why should I derive anything to gain the
access? On the other side, let I derive from a type which implementation
is
a black box to me. I don't want to know the implementation details.
Thats just due to bad programming, you should refactor, if user of a class
needs access to protected members, its just badly programmed and need
refactoring of the code. But some people are lazy...
C++ programmers have massive problems with deciding "private" vs.
"protected." The reason is obvious, this decision cannot be made by the
designer of the class. Forcing it too early is a problem. So they go:
#define private protected
I suggest this is why you wanted macros? (:-))
definately not !:)
You could not do this in my language.
+ contracted exceptions
try, throw, catch, and finally.
I meant that each operation has a contract of the exceptions, which may
propagate out of it. The exception contracts are statically checked and
inherited from parent typed. (Java, but with lessons learned.)
Okay. Please elaborate.
Java lacks mechanism of working with these contracts. You should be able
to
say: A can raise what B raises, or A does not raise if B does not etc.
Okay.
+ statically checked pre-/postconditions, invariants
Yes like Eiffle, nice, I had though about these.
No, unlike Eiffel. Meyer did it wrong, IMO. In Eiffel they are
assertions.
I meant correctness checks, i.e. everything happens before the run.
Otherwise it makes no sense.
Really you want both, compile time assertions and runtime ones if they
are
not resolvable at compile time. Maybe they want to be separate
syntatically
though.
I disagree. Run-time is evil, it is poor man's testing. One writes an
assertion and believes he solved the problem.
I think we see things differently here, but they can be misused.
Run-time checks are conceptually wrong. What does a client when a check
fails? If that was a contract violation, it could do nothing, because the
program can be in ANY state. If the state is somehow defined, then that is
a part of the contract, like Overflow_Error or End_Of_File_Error. In that
case it is not a check, but a valid condition.
All runtime assertions do not appear on the command line unless you set a
flag they usually are written to a log file, which maybe sent over the
internet automatically.
+ abstract interfaces for standard container types (array, record)
+ abstract interfaces for referential types
+ abstract interfaces for aggregates
+ dynamically constrained types
Runtime typing, runtime constraints ? Please clarify ?
Consider an array type, like string. String is unconstrained because its
length is unknown. But this does not mean you need dynamically allocated
strings like in C++. In 90% cases all string objects are constrained
(have
known length) on the caller side. But the callee is works with an
unconstrained formal object. This is a very powerful model of type
parametrization without generics.
Pretty useless in this example,
No, it is an extremely useful one. It allows a function to return a string
on the *stack*. Try it in C++.
Rathe use std:sting myself.
+ downward closures
please elaborate.
Passing a function as a parameter. The function carries its context
with.
Please give an example.
Consider function Integrate that integrates another function on some
interval. The integrated function is passed as a parameter. Now consider:
N : Integer := Read_From_Keyboard;
function Power (X : Float) return Float is
begin
return X ** N:
end Power;
begin
Y := Integrate (0.0, 1.0, Power);
Power is a downward closure, it carries N with when passed to Integrate.
The value of N is unknown until run-time.
Okay a closure :)
To me any function is virtual. I see no reason to have other kind of
functions. They breaks out of the model. If you have multiple dispatch,
free functions vanish.
Not necessarily ? Please elaborate.
I did.
what do you mean by free functions ?
+ an ability to have polymorphic objects with value semantics (follows
from OO 2)
Dont follow please explain your model properly.
See above.
Still dont understand.
Derive a new type from Boolean (Belnap's four-state logical value, for
instance). Override "and", "or" etc. Create an object of the specific type
you don't know before run-time if it Boolean or Belnap. Pass it to a
subprogram. Do you want it passed by reference? I don't.
This is just covarience/contravarience stuff.
Any contenders ?
We will forget about the contenders :)
The problem is that to make that list right is a huge problem. You
forgot
the mist important thing, the requirements of how the above aspects
shall
be implemented, Say you add to multiple dispatch and obvious
requirement: "no dispatch may fail at run time," and you get a serious
problem, since
nobody, AFAIK, knows how to achieve that.
I was not aware of anything like this with multiple dispatch could
produce
exceptions if there are undefined usages though.
Lisp's MOF seems to have implemented MD fine.
Could you please elaborate and maybe give an example please.
When you derive S from T and inherit some f, the language shall force
you
to define all implementations of f for all possible combinations of the
parameters if it cannot invent an implementation by itself. Consider:
f : T x P
you derive S from T, now there are
f : T x P
-----------------------------
f : S x P (inherited)
let's derive R from P, now we have
f : T x P
f : S x P
-----------------------------
f : T x R (inherited)
f : S x R (inherited)
At any step, the compiler shall ensure that each slot in the dispatching
table of f is defined either per inheritance or else by the programmer.
No
undefined slots.
Okay.
Now, derive S and R in two separately compiled modules. See the problem?
No you lost me...
Aaron
.
- Follow-Ups:
- Re: The Language I want
- From: Dmitry A. Kazakov
- Re: The Language I want
- References:
- The Language I want
- From: Aaron Gray
- Re: The Language I want
- From: Aaron Gray
- Re: The Language I want
- From: Dmitry A. Kazakov
- Re: The Language I want
- From: Aaron Gray
- Re: The Language I want
- From: Dmitry A. Kazakov
- Re: The Language I want
- From: Aaron Gray
- Re: The Language I want
- From: Dmitry A. Kazakov
- The Language I want
- Prev by Date: Re: The Language I want
- Next by Date: Re: The Language I want
- Previous by thread: Re: The Language I want
- Next by thread: Re: The Language I want
- Index(es):
Relevant Pages
|
Loading