From: Jeffrey Carter on 8 Aug 2010 16:34
On 08/08/2010 06:11 AM, Natacha Kerensikova wrote:
> Well actually the requirements were presented in the beginning: I've
> got a S-expression configuration file, a directory of static files, a
> directory of S-expression templates and a directory of S-expression
> data to populate the templates. And I want to respond to HTTP request
> with either a static file or an expanded template. Now I might
> misunderstanding the word "requirements", but what I actually consider
> as requirements is the above without any "S-expression" occurrence,
> the rest being implementation choices. "S-expression" might be part of
> the requirements to use existing data, but then again another format
> can be chosen provided a converted from S-expression is also coded.
Most of what you presented seem more like implementation decisions
(S-expressions for the configuration information, S-expressions for the page
templates) than requirements. Even discussion of files and directories might be
premature, depending on the higher level requirements. A web server that can be
used in an embedded system as the external interface as well as as a stand-alone
system would need a more abstract view of permanent storage, for example.
Of course, sometimes implementation decisions are made by others and become part
of one's requirements, but I wouldn't expect that in a personal project. And the
existence of an existing library can be an important factor when masking such
I wasn't saying that implementing an S-expression library, or deciding to use it
at a low level in your project, was a bad thing. I was viewing this project as a
separate thing from your S-expression library.
> Thanks for the pointer, however I'm already afraid learning only Ada
> is too much for me (I've tried with C++ and it's a language much too
> complex to fit in my head (especially the STL), and I hope Ada is
> simple enough), learning both Ada and AWS at the same time will
> probably be way too much. However I haven't decided yet whether I will
> actually begin with this project, I might try to code something
> simpler before that (which will also need S-expressions, hence my
> beginning with that library). In that case, I might be confident
> enough in my Ada before starting the web project, and then go for AWS.
I think something like AWS would help you learn Ada. You need to look at
existing code as well as write your own. Starting with the library has good and
bad points. It's a fairly small, contained project, which is good. On the other
hand, the first things you write in Ada are probably not going to be great. In a
few months you'll probably look at the library and want to make significant
changes to it.
Ada is simpler than C++. It's also fairly well designed, so most features are
orthogonal, which simplifies learning the language.
> Actually, that's very similar to what I thought too. It's just that
> I've already thought so much about this project that I'm further down
> the road, and I tried to fit everything in the one-dimension of a
I'm glad to hear that. Perhaps I simply misinterpreted your presentation.
> That's actually a pretty strange thing I've never encountered yet in
> other coders I know, I first spend a lot of time thinking before
> writing the first line of code (or that particular case, before even
> managing to install the compiler). I also spend much less time
> debugging, though I can't tell whether they are related or whether one
> of them is more efficient than the other.
Excellent. The whole point of Ada is thinking before coding, so you'll probably
find that Ada supports your way of doing things. It's a common experience that
if you did think first, by the time you get your code to compile, it works
correctly. Ada people don't do a lot of debugging; I can't remember the last
time I used a debugger. When we do have problems, they tend to be logic errors
rather than typos.
> Unless I'm very misunderstanding and/or vary naive, I've got the
> feeling our approaches are not that different, and differ mostly in
> the order of implementation, which indeed doesn't change that much in
> the final result.
You may well be right, in which case you'll likely find Ada to be a good fit for
your way of approaching things.
"I wave my private parts at your aunties."
Monty Python & the Holy Grail
--- news://freenews.netfront.net/ - complaints: news(a)netfront.net ---
From: Dmitry A. Kazakov on 8 Aug 2010 16:39
On Sun, 08 Aug 2010 16:03:22 -0400, Robert A Duff wrote:
> For scalars, the primitive operations mostly don't know the
> subtype bounds -- they are operations of the type. So this
> wouldn't fit into Ada well.
But array subtypes silently modify their operations or, if you want,
parametrize them using the dope. A modular subtype would have a dope as
>> ...then they could be used as indices.
> The problem I was alluding to is that if you have
> an unconstrained array type, sooner or later you might
> have an empty one. So you want bounds 0..-1, but -1
> wraps around.
Empty range does not have bounds. What are bounds of
type Empty is mod 0; -- Illegal in Ada, but must be legal
> Same thing with a "for" loop that goes from T'First up to
If ranges (contiguous sets of indices) were proper types you would be able
to construct them in many different ways. E.g.
function ":" (From : Index; Length : Universal_Integer)
L := 0
for I in T'First :L loop
instead of what you can find in every Ada program:
for I in T'First..T'First + L - 1 loop
or for enumerations:
for I in T'First..T'Val (T'Pos (T'First) + L - 1) loop
which does not work anyway...
> If 2..10 wrapped around, then you'd want range 2..1, which
> has the same problem.
2..1 actually is 2,3,4,5,6,7,8,9,1
Modular numbers are not ordered.
Dmitry A. Kazakov
From: Robert A Duff on 8 Aug 2010 17:08
"Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> writes:
> On Sun, 08 Aug 2010 16:03:22 -0400, Robert A Duff wrote:
>> For scalars, the primitive operations mostly don't know the
>> subtype bounds -- they are operations of the type. So this
>> wouldn't fit into Ada well.
> But array subtypes silently modify their operations or, if you want,
> parametrize them using the dope.
Yes, and discriminated subtypes are similar to arrays in that way.
The dividing line is "scalar" vs. "composite". (I'm not sure that's
a good idea, but that's Ada.) You are suggesting to make modular
types (a kind of scalar) work more like composites, which doesn't
fit well, even if it's a good idea in the abstract.
I actually have no opinion whether it's a good idea, because I
don't like modular types in the first place. ;-)
I didn't mention "access" above, which are "elementary" but not
"scalar". Constrained access subtypes are a nightmare!
>... A modular subtype would have a dope as
They already do, but the arithmetic ops don't consult that dope.
>>> ...then they could be used as indices.
>> The problem I was alluding to is that if you have
>> an unconstrained array type, sooner or later you might
>> have an empty one. So you want bounds 0..-1, but -1
>> wraps around.
> Empty range does not have bounds.
Except that in Ada, they do. An empty String is (1..0).
It could also be 10..9 or even -100..-10_000_000, but
that's not a good idea.
>...What are bounds of
> type Empty is mod 0; -- Illegal in Ada, but must be legal
>> Same thing with a "for" loop that goes from T'First up to
> If ranges (contiguous sets of indices) were proper types you would be able
> to construct them in many different ways. E.g.
> function ":" (From : Index; Length : Universal_Integer)
> return Index'Range
> L := 0
> for I in T'First :L loop
> instead of what you can find in every Ada program:
> for I in T'First..T'First + L - 1 loop
> or for enumerations:
> for I in T'First..T'Val (T'Pos (T'First) + L - 1) loop
> which does not work anyway...
>> If 2..10 wrapped around, then you'd want range 2..1, which
>> has the same problem.
> 2..1 actually is 2,3,4,5,6,7,8,9,1
> Modular numbers are not ordered.
But they are -- they have "<", and "for" and so on.
Perhaps they _should_ be unordered, but I won't agree or disagree,
since I think in an ideal world they should be banished.
By the way, one defense of modular types I've heard is that
they are used in mathematics. True. But mathematicians do
not use _implicit_ mod. They say things like "X = Y (mod N)",
which is pronounced "X is congruent to Y (modulo N)".
Congruent, not equal.
From: Dmitry A. Kazakov on 9 Aug 2010 02:50
On Sun, 08 Aug 2010 17:08:50 -0400, Robert A Duff wrote:
> "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> writes:
> I actually have no opinion whether it's a good idea, because I
> don't like modular types in the first place. ;-)
The implementation or the idea? Would you agree that objects with some
properties of modular integers have place in Ada programs which do not
> I didn't mention "access" above, which are "elementary" but not
> "scalar". Constrained access subtypes are a nightmare!
Yes, because the language should decide whether the constraint does
influence the behavior (all operations potentially), or is a kludge that
prohibits some values when assigned or passed. I understand the motivation
why Ada 83 chosen the second, but it does not make it right. Assignment is
an operation as any other.
>> Empty range does not have bounds.
> Except that in Ada, they do. An empty String is (1..0).
> It could also be 10..9 or even -100..-10_000_000, but
> that's not a good idea.
Yes, because it is wrong. Doing something wrong always will hit back.
>> Modular numbers are not ordered.
> But they are -- they have "<", and "for" and so on.
"<" is wrong when non-transitive. I wished Ada clarified difference between
enumeration and total order.
> Perhaps they _should_ be unordered, but I won't agree or disagree,
> since I think in an ideal world they should be banished.
I think they could be fixed.
> By the way, one defense of modular types I've heard is that
> they are used in mathematics. True.
> But mathematicians do
> not use _implicit_ mod. They say things like "X = Y (mod N)",
> which is pronounced "X is congruent to Y (modulo N)".
> Congruent, not equal.
The mathematical notation (mod N) is untyped. It applies to any natural
numbers and what is worse you have to add it at each point of the program
you use the type.
Dmitry A. Kazakov
From: Natacha Kerensikova on 9 Aug 2010 05:55
On Aug 8, 5:15 pm, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
> On Sun, 8 Aug 2010 06:49:09 -0700 (PDT), Natacha Kerensikova wrote:
> > On Aug 8, 3:01 pm, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
> >> No I do. But you have defined it as a text file. A streamed text file is a
> >> sequence of Character items.
> > Actually, I didn't. I only defined it as a bunch of byte sequences
> > organized in a certain way.
> I see. This confuses things even more. Why should I represent anything as a
> byte sequence? It already is, and in 90% cases I just don't care how the
> compiler does that. Why to convert byte sequences into other sequences and
> then into a text file. It just does not make sense to me. Any conversion
> must be accompanied by moving the thing from one medium to another.
> Otherwise it is wasting.
Representing something as a byte sequence is serialization (at least,
according to my (perhaps wrong) definition of serialization). Actually
there is no byte sequences converted into other sequences converted
into a text file. The only conversion is from in-memory representation
(which happens to be also a byte sequence, but maybe not contiguous or
context-dependent or whatever, that's besides the point) into a
serialized byte sequence.
S-expressions are not a format on top or below that, it's a format
*besides* that, at the same level. Objects are serialized into byte
sequences forming S-expression atoms, and relations between objects/
atoms are serialized by the S-expression format. This is how one get
the canonical representation of a S-expression.
Now depending on the situation one might want additional constrains on
the representation, for example human-readability or being text-based,
and the S-expression standard defines non-canonical representations
for such situations.
> > I know very well these differences, except octet vs character,
> > especially considering Ada's definition of a Character. Or is it only
> > that Character is an enumeration while octet is a modular integer?
> The difference is that Character represents code points and octet does
> atomic arrays of 8 bits.
Considering Ada's Character also spans over 8 bits (256-element
enumeration), both are equivalent, right? The only difference is the
intent and the meaning of values, right? (unlike byte vs octet, where
quantitative differences might exist on some platforms).
> > This leads to a question I had in mind since quite early in the
> > thread, should I really use an array of Storage_Element, while S-
> > expression standard considers only sequences of octets?
> That depends on what are you going to do. Storage_Element is a
> machine-dependent addressable memory unit. Octet is a machine independent
> presentation layer unit, a thing of 256 independent states. Yes
> incidentally Character has 256 code points.
Actually I've started to wonder whether Stream_Element might even more
appropriated: considering a S-expression atom is the serialization of
an object, and I guess objects which know how to serialize themselves
do so using the Stream subsystem, so maybe I could more easily
leverage existing serialization codes if I use Stream_Element_Array
for atoms. But then I don't know whether it's possible to have object
hand over a Stream_Element_Array representing themselves, and I don't
know either how to deal with cases where Stream_Element is not an
> >> Once you matched "tcp-connect", you know all the types of the following
> >> components.
> > Unfortunately, you know "80" is a 16-bit integer only after having
> > matched "port".
> Nope, we certainly know that each TCP connection needs a port. There is
> nothing to resolve since the notation is not reverse. Parse it top down, it
> is simple, it is safe, it allows excellent diagnostics, it works.
(tcp-connect (host foo.example) (port 80))
(tcp-connect (port 80) (host foo.example))
Both of these are semantically equivalent, but know which of the tail
atom is a 16-bit integer and which is the string, you have to first
match "port" and "host" head atoms.
Or am I misunderstanding your point?
> >>> This is not always the
> >>> case, for example it might be necessary to build an associative array
> >>> from a list of list before being able to know the type of non-head
> >>> atoms,
> >> What for? Even if such cases might be invented, I see no reason to do that.
> >> It is difficult to parse, it is difficult to read. So why to mess with?
> > For example, you might have a sub-S-expression describing a seldom
> > used object that is expensive to build, wouldn't you want to be sure
> > you actually need it before building it?
> See above, if you parse top down, you know if you need that object before
> begin. Then having a bracketed structure, it is trivial to skip the
> object's description without construction. Just count brackets.
Well in that example I was considering something outside from the S-
expression selects which object to use. For example a database
containing thousands of templates or whatever, and user selection
picking only one of them.
Thanks for your patience with me,