Attributes VS Properties

D

David Mark

Last I checked, shortness was one attribute that defined "concise".

But do short identifiers lead to concise code? I'd say only in a very
literal (and narrow) sense. Concise code is produced by eliminating
redundancies (like with these create element wrappers).
I don't think that's a good idea.

Noted.
 
T

Thomas 'PointedEars' Lahn

David said:
I assure you I am. :)


It's not a contest

Well, *you* want My Library used above others, most notably jQuery, do you
not? Insofar it is a contest for sure.
and those are apples and oranges. The
createElementWithAttributes method is built on top of createElement.
I think the names make that clear and the longer wrapper takes care of
the issue with the type property. ;)

That doesn't make sense. The extension can be facilitated with one method
with an optional argument.
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.

Because it is a long name?

Yes. A long name, hard to remember to begin with.
Then do this:-

var myCoolMethod = API.createAndAppendElementWithAttributes;

myCoolMethod('input', { name:'test', type:'button', value='test' },
document.forms['myform']);

If `API' has any meaning, that is not the same.


PointedEars
 
D

David Mark

I assure you I am. :)
It's not a contest

Well, *you* want My Library used above others, most notably jQuery, do you
not? Insofar it is a contest for sure.
and those are apples and oranges. The
createElementWithAttributes method is built on top of createElement.
I think the names make that clear and the longer wrapper takes care of
the issue with the type property. ;)

That doesn't make sense. The extension can be facilitated with one method
with an optional argument.
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.
Because it is a long name?

Yes. A long name, hard to remember to begin with.

How is that hard to remember?
Then do this:-
var myCoolMethod = API.createAndAppendElementWithAttributes;
myCoolMethod('input', { name:'test', type:'button', value='test' },
document.forms['myform']);

If `API' has any meaning, that is not the same.

API has the meaning I gave previously. And it is the same. None of
the methods cares what - this - is set to. Why should they when it
would just foul up calls like the above. ;)
 
T

Thomas 'PointedEars' Lahn

David said:
But do short identifiers lead to concise code?

*Shorter* identifiers than this (`createElementWithAttributes') lead to
more concise and easier readable code for sure.
I'd say only in a very literal (and narrow) sense.

Well, from what I have read you have been doing it before: API.getEBI().
To be consistent, you would need to rename it to API.getElementById(), or
rename API.createElementWithAttributes() to API.createEWA() and the like.

However, API.createElement() with an optional argument strikes me as the
better choice.
Concise code is produced by eliminating redundancies (like with these
create element wrappers).

You should listen to your own words.

As for the createElement...AndAppend() method, you should consider the GNU
approach instead: One tool for one purpose (here: one method for one
purpose). Their combination makes the difference, makes the API robust and
flexible.


PointedEars
 
D

David Mark

*Shorter* identifiers than this (`createElementWithAttributes') lead to
more concise and easier readable code for sure.


Well, from what I have read you have been doing it before: API.getEBI().
To be consistent, you would need to rename it to API.getElementById(), or
rename API.createElementWithAttributes() to API.createEWA() and the like.

However, API.createElement() with an optional argument strikes me as the
better choice.


You should listen to your own words.

I do. :)
As for the createElement...AndAppend() method, you should consider the GNU
approach instead: One tool for one purpose (here: one method for one
purpose). Their combination makes the difference, makes the API robust and
flexible.

You misunderstand something. There is already a createElement
method. On top of that, there is a createElementWithAttributes
wrapper. You can use either. The whole library is built in layers
like that.

Here's the third tier for element creation:-

createAndAppendElementWithAttributes = function(tag, attributes,
appendTo, docNode) {
var el = createElementWithAttributes(tag, attributes,
docNode);
var name = attributes.name;
if (el) {
appendTo.appendChild(el);
if (name) {
el.name = name;
if (el.tagName.toLowerCase() == 'iframe' &&
isHostObjectProperty(el, 'contentWindow')) {
el.contentWindow.name = name;
}
}
}
return el;
};

I can tell you for sure that if you need to create a DOM structure on
the fly that includes forms, iframes, images, etc., such wrappers are
invaluable (and eliminate a lot of redundancy). The layer(s) used
depends on the context (as always). If you use the lower level
wrappers (e.g. createElement), you have to know a bit more about what
you are doing than with the higher-ups. That's another common theme.
You can trust that _I_ know what I'm doing. ;)

And it isn't lost on me that this latest wrapper cannot be used to
insert before a specific node. That operation has always been handled
at the OO level:-

D().createElementWithAttributes(...).insertBefore(el);
D().createElementWithAttributes(...).insertAfter(el);

But I don't care for that at this point, so I will likely move the
insertBefore/After logic down a level. It won't invalidate the
interface, but will make it more flexible by adding additional API
methods (and perhaps a new option for the existing wrappers).
 
T

Thomas 'PointedEars' Lahn

David said:
You misunderstand something

No, I don't think so.
There is already a createElement method.

I figured as much.
On top of that, there is a createElementWithAttributes
wrapper. You can use either. The whole library is built in layers
like that.

Then I'd rather not use or recommend it.
Here's the third tier for element creation:-

createAndAppendElementWithAttributes = function(tag, attributes,
appendTo, docNode) {
var el = createElementWithAttributes(tag, attributes,
docNode);

I did that one wrong once, too. Better to pass the reference to the object
and use that reference instead of passing strings on to a subroutine.
Reduces stack usage and is much more flexible. Like I said, one tool for
one purpose. Makes shorter identifiers and argument lists, too.


PointedEars
 
M

Matt Kruse

The problem is that I already have a markup with hidden input fields
which now has to be shown to the user if he clicks on the checkbox
(nevermind why).
The simplest solution was to change type property using javascript ...

Wouldn't it be simpler to just hide an <input type="text"> element
using CSS, then show it?

Changing element types isn't reliable and should always be avoided.

Matt Kruse
 
I

Ivan S

The obvious solution is not to toggle the `type' of the control but the
visibility of the element: Use the `visibility' or `display' style
properties to hide/show it.  

I think you misunderstood the problem. Markup with hidden inputs was
already there. So, there is / was no point in making *hidden* inputs
visible ... but if they were text fields ... :)

I just had to change markup and make that fields invisible ... now
it's working fine.
 
D

David Mark

No, I don't think so.


I figured as much.

You figured right. It's there because My Library supports XHTML as well
as the requisite HTML (something that will soon be optional through the
builder). Also, it would be there any as there is the chance that
document.createElement will not exist (or will be unusable). In those
cases, API.createElement is pruned. Therefore, the calling app's
gateway starts out like:-

if (API && API.createElement) {
// Good to create elements
}

The alternative without the wrapper is to do all of the feature testing
inline, which is hardly concise (or readable) and certainly prone to
mistakes (e.g. bad pastes).
Then I'd rather not use or recommend it.

You aren't making any sense at all. The layers are good. ISTM that was
your argument to begin with. Tangling everything up in one layer is bad
(see jQuery, Prototype, etc.)
I did that one wrong once, too.

You never did that one at all. I _just_ wrote it.
Better to pass the reference to the object
and use that reference instead of passing strings on to a subroutine.

You would have to pass a string to a function that _creates_ elements.
So you would use the middle tier (createElementWithAttributes), which
returns a reference to an element. Then you can append/insertBefore the
element. As mentioned, you have to know a bit more about what you are
doing as you go down in levels. In this case, you would need to account
for the name property issue.
Reduces stack usage and is much more flexible. Like I said, one tool for
one purpose. Makes shorter identifiers and argument lists, too.

You still aren't making any sense. The lower level methods (e.g.
createElement) have shorter identifiers and argument lists. As you go
up each level, the identifiers and argument lists get longer, which is
to be expected. Use whatever layer fits your needs. It's all good. ;)
 
T

Thomas 'PointedEars' Lahn

Ivan said:
I think you misunderstood the problem. Markup with hidden inputs was
already there. So, there is / was no point in making *hidden* inputs
visible ... but if they were text fields ... :)

You wanted to toggle the `type' of the already inserted `input' element
from `hidden' to `text' (and perhaps back), and failed to do that because
MSHTML did not allow it, did you not?
I just had to change markup and make that fields invisible ... now
it's working fine.

For fitting values of "fine". I have already told you that this is it is
poor UI design, and offered a better alternative.


PointedEars
 
D

David Mark

like.


I do. :)




You misunderstand something. There is already a createElement
method. On top of that, there is a createElementWithAttributes
wrapper. You can use either. The whole library is built in layers
like that.

Here's the third tier for element creation:-

createAndAppendElementWithAttributes = function(tag, attributes,
appendTo, docNode) {
var el = createElementWithAttributes(tag, attributes,
docNode);
var name = attributes.name;
if (el) {
appendTo.appendChild(el);
if (name) {
el.name = name;
if (el.tagName.toLowerCase() == 'iframe' &&
isHostObjectProperty(el, 'contentWindow')) {
el.contentWindow.name = name;
}
}
}
return el;
};

I can tell you for sure that if you need to create a DOM structure on
the fly that includes forms, iframes, images, etc., such wrappers are
invaluable (and eliminate a lot of redundancy). The layer(s) used
depends on the context (as always). If you use the lower level
wrappers (e.g. createElement), you have to know a bit more about what
you are doing than with the higher-ups. That's another common theme.
You can trust that _I_ know what I'm doing. ;)

And it isn't lost on me that this latest wrapper cannot be used to
insert before a specific node. That operation has always been handled
at the OO level:-

D().createElementWithAttributes(...).insertBefore(el);
D().createElementWithAttributes(...).insertAfter(el);

Oops, you can probably tell I don't use the OO interface (never even
include it in the build).

E(D().createElementWithAttributes(...)).insertBefore(el);

The createElement* methods do not return wrapped elements. I toyed with
the idea of making all of the methods return wrapped elements (as
opposed to element references), but decided most apps would be better
off deciding what to do with the reference (no superfluous wrapper
objects are created and discarded). Speaking of that, I prefer:-

var elNew = D().createElementWithAttributes(...);
E(elNew}.insertBefore(el);

....or even:

var myDoc = D();
var elNew = myDoc.createElementWithAttributes(...);
var myEl = E(elNew);
myEl.insertBefore(el);

....as then you can re-use the wrapper objects (see the load methods).

Beats the living shit out of dollar signs for everything. ;)
 
D

David Mark

David said:
You figured right. It's there because My Library supports XHTML as well
as the requisite HTML (something that will soon be optional through the
builder). Also, it would be there any as there is the chance that
document.createElement will not exist (or will be unusable). In those
cases, API.createElement is pruned. Therefore, the calling app's
gateway starts out like:-

if (API && API.createElement) {
// Good to create elements
}

The alternative without the wrapper is to do all of the feature testing
inline, which is hardly concise (or readable) and certainly prone to
mistakes (e.g. bad pastes).


You aren't making any sense at all. The layers are good. ISTM that was
your argument to begin with. Tangling everything up in one layer is bad
(see jQuery, Prototype, etc.)


You never did that one at all. I _just_ wrote it.


You would have to pass a string to a function that _creates_ elements.
So you would use the middle tier (createElementWithAttributes), which
returns a reference to an element. Then you can append/insertBefore the
element. As mentioned, you have to know a bit more about what you are
doing as you go down in levels. In this case, you would need to account
for the name property issue.


You still aren't making any sense. The lower level methods (e.g.
createElement) have shorter identifiers and argument lists. As you go
up each level, the identifiers and argument lists get longer, which is
to be expected. Use whatever layer fits your needs. It's all good. ;)

You figured right. It's there because My Library supports XHTML as well
as the requisite HTML (something that will soon be optional through the
builder). Also, it would be there any as there is the chance that
document.createElement will not exist (or will be unusable). In those
cases, API.createElement is pruned. Therefore, the calling app's
gateway starts out like:-

if (API && API.createElement) {
// Good to create elements

}

The alternative without the wrapper is to do all of the feature testing
inline, which is hardly concise (or readable) and certainly prone to
mistakes (e.g. bad pastes).





You aren't making any sense at all. The layers are good. ISTM that was
your argument to begin with. Tangling everything up in one layer is bad
(see jQuery, Prototype, etc.)





You never did that one at all. I _just_ wrote it.


You would have to pass a string to a function that _creates_ elements.
So you would use the middle tier (createElementWithAttributes), which
returns a reference to an element. Then you can append/insertBefore the
element. As mentioned, you have to know a bit more about what you are
doing as you go down in levels. In this case, you would need to account
for the name property issue.


You still aren't making any sense. The lower level methods (e.g.
createElement) have shorter identifiers and argument lists. As you go
up each level, the identifiers and argument lists get longer, which is
to be expected. Use whatever layer fits your needs. It's all good. ;)

Unless perhaps you mean the lack of a setAttributes (which would of
course take an element reference) wrapper on top of setAttribute.
That's a hole for sure, but easily plugged (in fact it is in the sequel).
 
T

Thomas 'PointedEars' Lahn

David said:
Thomas said:
No, I don't think so.


I figured as much.

You figured right. It's there because My Library supports XHTML as well
as the requisite HTML (something that will soon be optional through the
builder). [...]

Non sequitur, though.
You aren't making any sense at all.

Perhaps after you have read below.
The layers are good.

Not as implemented, no.
ISTM that was your argument to begin with.

No, you must have completely misunderstood me.
Tangling everything up in one layer is bad
(see jQuery, Prototype, etc.)
Exactly.


You never did that one at all. I _just_ wrote it.

As it happens, JSX has a little longer history than My Library. Yes, I did
that one before, and have found it to be the wrong approach. That is, the
methodology; not exactly this code, of course.
You would have to pass a string to a function that _creates_ elements.
So you would use the middle tier (createElementWithAttributes), which
returns a reference to an element. Then you can append/insertBefore the
element. As mentioned, you have to know a bit more about what you are
doing as you go down in levels. In this case, you would need to account
for the name property issue.

I think you misunderstand me. Instead of wrapping everything into one
method (which, regardless of the layering, is not much different from
jQuery's approach, BTW), I would do (or have done) something along:

var o = _createElement("foo", {bar: "baz"}, d);
var o2 = _createElement("blurb", {bla: "blue"}, d);
_appendChild(o, o2);

instead of

var o2 = _createElement("blurb", {bla: "blue"}, d);
_createElementAndAppendChild("foo", {bar: "baz"}, o2, d);

AISB, one tool for one purpose.
You still aren't making any sense. The lower level methods (e.g.
createElement) have shorter identifiers and argument lists.

But not the higher-level ones because you need to drag the rest of the
argument list of the lower-level ones with you. And should a considerable
change be necessary in one of the lower-level methods that cannot be
compensated by the arguments list of the higher-level method, all methods
need to change signature. BTDT; never again.
As you go up each level, the identifiers and argument lists get longer,
which is to be expected.

Maybe in your book, not in mine. Long argument lists and needless stacking
are an API killer.


PointedEars
 
D

David Mark

Thomas said:
David said:
Thomas said:
David Mark wrote:
Thomas 'PointedEars' Lahn wrote:
As for the createElement...AndAppend() method, you should consider
the GNU approach instead: One tool for one purpose (here: one method
for one purpose). Their combination makes the difference, makes the
API robust and flexible.
You misunderstand something
No, I don't think so.

There is already a createElement method.
I figured as much.
You figured right. It's there because My Library supports XHTML as well
as the requisite HTML (something that will soon be optional through the
builder). [...]

Non sequitur, though.
You aren't making any sense at all.

Perhaps after you have read below.
Perhaps.
The layers are good.

Not as implemented, no.

That has no real meaning. These are about as simple as wrappers get.
There's only so much to point out (e.g. setAttributes is a missing
piece). Pointing out nothing isn't helping at all.
No, you must have completely misunderstood me.

That's possible.
Good.


As it happens, JSX has a little longer history than My Library. Yes, I did
that one before, and have found it to be the wrong approach. That is, the
methodology; not exactly this code, of course.

I understood what you meant. :) Still, I don't see what your point is
with regard to createElementWithAttributes. It definitely rocks!
I think you misunderstand me. Instead of wrapping everything into one
method (which, regardless of the layering, is not much different from
jQuery's approach, BTW), I would do (or have done) something along:

It is nothing like jQuery's approach. Everything in jQuery is tangled
up. You can't peel away layers of jQuery at all. I suppose if they
could, they'd have a builder like this:

http://www.cinsoft.net/mylib-builder.asp
var o = _createElement("foo", {bar: "baz"}, d);
var o2 = _createElement("blurb", {bla: "blue"}, d);
_appendChild(o, o2);

Aha! Now we are getting somewhere. That last one is useless. Change to:-

var el = createElement(...);
var el2 = createElement(...);
el.appendChild(el2);

....as there's no need for an appendChild wrapper. As for feature
detection, just check API.createElement*. It would seem unlikely that
an implementation would feature createElement but not appendChild, but
you never know. ;)

if (API.createElement) {
var el = createElement(...);
var el2 = createElement(...);
if (API.isHostMethod(el, 'appendChild')) { // Likely superfluous check
el.appendChild(el2);
}
}

if (API.createAndAppendElementWithAttributes) {
...
}

Clearly the latter will be pruned if the appendChild method is not
featured by the DOM.

if (html && isHostMethod(html, 'appendChild')) {
createAndAppendElementWithAttributes = function(tag, attributes,
appendTo, docNode) {
var el = createElementWithAttributes(tag, attributes, docNode);
var name = attributes.name;
if (el) {
appendTo.appendChild(el);
if (name) {
el.name = name;
}
if (el.tagName.toLowerCase() == 'iframe' &&
isHostObjectProperty(el, 'contentWindow')) {
el.contentWindow.name = name;
}
}
return el;
};
}
instead of

var o2 = _createElement("blurb", {bla: "blue"}, d);
_createElementAndAppendChild("foo", {bar: "baz"}, o2, d);

AISB, one tool for one purpose.

But you didn't notice that the more granular tools are one floor down. ;)
But not the higher-level ones because you need to drag the rest of the
argument list of the lower-level ones with you.

I take it you only write very low-level API's. At some point somebody
has to build on the foundation. If the project is a GP library for
non-programmers, it has to include higher-level methods and objects.
And should a considerable
change be necessary in one of the lower-level methods that cannot be
compensated by the arguments list of the higher-level method, all methods
need to change signature. BTDT; never again.

I'm aware of that consideration. I don't deliberately paint myself into
corners (and know how to extricate if I make a mistake).
Maybe in your book, not in mine. Long argument lists and needless stacking
are an API killer.

Long is relative. As I explained, createElement has one (or two if you
need to specify another document) argument. Not unsurprisingly, the
createElementWithAttributes wrapper has an additional argument for the
attributes. No "API killers" there. :)
 
G

Garrett Smith

Thomas said:
David said:
And that wrapper is API.createElementWithAttributes:-

You can't be serious. What's wrong with `API.createElement', the `API'
aside (see below)?
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.
Generalized element builders.

There are too many edge cases support. There are problems with nodes
that can't accept other nodes, special handling for certain attributes
(cellPadding, name).

If the problem is narrower there aren't as many edge cases. For example,
a hidden method `createCalendarOnDemand` creates HTML for the calendar
widget. It has no options to determine the HTML structure, and so there
is not testing multiple contexts and configurations. I like that.
 
D

David Mark

Garrett said:
Thomas said:
David said:
If you build a new library, it will now "work" for all but IE8
standards mode. But I don't want it to work like that, so soon it
will fail for all. Always set the type attribute/property _first_ (or
use a wrapper that does that for you).
And that wrapper is API.createElementWithAttributes:-

You can't be serious. What's wrong with `API.createElement', the
`API' aside (see below)?
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.
Generalized element builders.

There are too many edge cases support.

That's meaningless.
There are problems with nodes
that can't accept other nodes, special handling for certain attributes
(cellPadding, name).

There are no issues if you have competently written wrappers. Of
course, that lets out... virtually everyone. As for problems of nodes
not accepting other nodes, that's inherent to the underlying DOM
interface, so is irrelevant for a wrapper (unless it claims to support
non-standard behavior).
If the problem is narrower there aren't as many edge cases. For example,
a hidden method `createCalendarOnDemand` creates HTML for the calendar
widget.

What calendar widget? And why does that method create HTML? Also,
aren't all methods on demand?
It has no options to determine the HTML structure, and so there
is not testing multiple contexts and configurations. I like that.

Yes, context specific solutions always trump GP. But we are talking
about (though not necessarily advocating) a GP library.
 
S

Scott Sauyet

David Mark wrote:
I think you misunderstand me.  Instead of wrapping everything into one
method (which, regardless of the layering, is not much different from
jQuery's approach, BTW), I would do (or have done) something along:

  var o = _createElement("foo", {bar: "baz"}, d);
  var o2 = _createElement("blurb", {bla: "blue"}, d);
  _appendChild(o, o2);

instead of

  var o2 = _createElement("blurb", {bla: "blue"}, d);
  _createElementAndAppendChild("foo", {bar: "baz"}, o2, d);

This is made even more pointed by the order of the arguments in that
last line. Why in the world would o2 be placed in the middle of the
set of parameters sent to the lower-level API? How is a developer
supposed to remember that order? The usual reasons for such strange
orderings is backward compatibility. It's possible that the last
parameter to both the createElement and the
createElementAndAppendChild did not exist in an earlier version of the
API and were added to the end so that existing code needed less
change. Either that or d is an optional argument that has to be
carried through, and you want all the optional ones at the end. But
if that's the case, implementation convenience is trumping solid API
design -- never a good idea.

One advantage to Thomas' suggestion is that you don't need to carry
this baggage through multiple levels of API.

But to me the main issue is the intellectual weight. Perhaps most of
the work I would need to do could be done through the upper-level
APIs, but I imagine that occasionally I would need to use the lower
levels too, right? At that point, I have to remember the simpler
lower-level versions and the more complex higher-level ones. Keeping
track of parameter order is an issue, but even remembering whether
it's called "createAndAppendElementWithAttributes" or
"createElementWithAttributesAndAppend" gets to be an intellectual
burden.

For example, in Java, the IO libraries are well layered, but this
comes at a heavy price for users. I'm going to try this from memory,
but would not be at all surprised if I'm wrong:

BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(
new File(filename))));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}

It's a bit of a feat to get that right if you haven't been using the
API for a while. Meanwhile in Python, I have little doubt about this
code:

f = open(filename, 'r')
for line in f:
print line,

The Python API simply has less to remember, less to get wrong. It is
less flexible, perhaps. But for most of my day-to-day work, I would
rather be using a simple-to-remember and simple-to-use API than one
with lots of bells and whistles.

Maybe in your book, not in mine.  Long argument lists and needless stacking
are an API killer.

Yes, *needless* stacking. It's not that stacking cannot be useful.
But if not done extremely carefully, it bloats an API and makes it
harder to remember and to effectively use.

-- Scott
 
S

Scott Sauyet

The Python API simply has less to remember, less to get wrong.  It is
less flexible, perhaps.  But for most of my day-to-day work, I would
rather be using a simple-to-remember and simple-to-use API than one
with lots of bells and whistles.

And I should have added, that when we do this in JS we can gain
flexibility with an options object:


var o = _createElement("foo");
var o = _createElement("foo", {attributes: {bar: "baz"});
var o = _createElement("foo", {attributes: {bar: "baz"}, docNode:
node, appendTo: parent});

-- Scott
 
D

David Mark

Scott said:
This is made even more pointed by the order of the arguments in that
last line.

It is because d (document) is an option used only with frames (another
layer of support that will be filtered by the builder shortly). JFTR,
the above functions are from the PE collection (though my
createElementWithAttributes has arguments in similar order).
Why in the world would o2 be placed in the middle of the
set of parameters sent to the lower-level API?

Because the optional one is best last.
How is a developer
supposed to remember that order?

You almost never use the optional one and the optional one is always last.
The usual reasons for such strange
orderings is backward compatibility.

Nothing strange above, other than the underscores.
It's possible that the last
parameter to both the createElement and the
createElementAndAppendChild did not exist in an earlier version of the
API and were added to the end so that existing code needed less
change.

Could be, but no.
Either that or d is an optional argument that has to be
carried through, and you want all the optional ones at the end.

It is optional and as such, it does not necessarily have to be carried
through (unless it is passed to the higher level function).
But
if that's the case, implementation convenience is trumping solid API
design -- never a good idea.

There's nothing like that going on with these simple wrappers. It
wouldn't make them better to move the optional document argument to the
middle.
One advantage to Thomas' suggestion is that you don't need to carry
this baggage through multiple levels of API.

What suggestion? I explained that he could do what he wanted to do with
my API, which is not very much unlike his.
But to me the main issue is the intellectual weight.

There's nothing intellectual about these simple wrappers.

var el = API.createElement('div');

var el = API.createElementWithAtttributes('div', { ... });

But wait, you want to use frames? How could that work?

var el = API.createElement('div', doc);

var el = API.createElementWithAtttributes('div', { ... }, doc);

Yes, just tack the optional document argument onto the end, exactly
where it should go.
Perhaps most of
the work I would need to do could be done through the upper-level
APIs, but I imagine that occasionally I would need to use the lower
levels too, right?

Sure, as in the above example.
At that point, I have to remember the simpler
lower-level versions and the more complex higher-level ones.

Not in the above example. There's nothing to remember.
Keeping
track of parameter order is an issue, but even remembering whether
it's called "createAndAppendElementWithAttributes" or
"createElementWithAttributesAndAppend" gets to be an intellectual
burden.

So create a macro. ;) Or do this (you should anyway):-

var myMethod = API.createAndAppendElementWithAttributes;

var el = myMethod(this, that, there);

And if you want to use frames:-

var el = myMethod(this, that, there, doc);

Yes, tack on the optional document argument, the only place it could
logically go.
For example, in Java, the IO libraries are well layered, but this
comes at a heavy price for users. I'm going to try this from memory,
but would not be at all surprised if I'm wrong:

BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(
new File(filename))));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}

It's a bit of a feat to get that right if you haven't been using the
API for a while. Meanwhile in Python, I have little doubt about this
code:

And what is that feat? Printing a file to the console? If so, Java
sucks for file IO and I am sure some smart egg has written a
higher-level console API.
f = open(filename, 'r')
for line in f:
print line,

That's better.
The Python API simply has less to remember, less to get wrong. It is
less flexible, perhaps. But for most of my day-to-day work, I would
rather be using a simple-to-remember and simple-to-use API than one
with lots of bells and whistles.

Yes, but how does that apply to the wrappers at hand? Could they
possibly be made simpler? About the only hole I see is a setAttributes
wrapper. I suppose you could add an append/insertBefore wrapper too
(those exist only in the OO layer in mine, which does leave gaps in the
lower levels).
Yes, *needless* stacking. It's not that stacking cannot be useful.
But if not done extremely carefully, it bloats an API and makes it
harder to remember and to effectively use.

Yes, I agree that needless stacking is bad. I just don't think it's
been shown that the three methods in question are needlessly stacked.
Each layer serves a specific purpose. There are problems with creation
and problems with appending. Each layer deals with its own problems.
 
T

Thomas 'PointedEars' Lahn

Garrett said:
Thomas said:
David said:
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.

Generalized element builders.

There are too many edge cases support. There are problems with nodes
that can't accept other nodes, special handling for certain attributes
(cellPadding, name).

If the problem is narrower there aren't as many edge cases. For example,
a hidden method `createCalendarOnDemand` creates HTML for the calendar
widget. It has no options to determine the HTML structure, and so there
is not testing multiple contexts and configurations. I like that.

You have failed to post a coherent follow-up. Please try again. General
characteristics of a coherent follow-up include, but are not limited to:
Correct and understandable language, reference to the statements in the
precursor or, as an exception, its precursors. Thank you in advance.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top