all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Should records be able to mimic primitive types?
@ 2017-04-04 22:00 Paul Eggert
  2017-04-05  1:09 ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Paul Eggert @ 2017-04-04 22:00 UTC (permalink / raw)
  To: Emacs development discussions

In looking at the 'record' feature recently added to master, I noticed 
that (record 'integer 'foo 'bar) returns a value V such that (type-of V) 
yields the symbol 'integer', even though V is not an integer. Is this 
intended? Or should 'record' and 'make-record' reject attempts to build 
records that pretend to be of primitive types?




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-04-04 22:00 Should records be able to mimic primitive types? Paul Eggert
@ 2017-04-05  1:09 ` Stefan Monnier
  2017-04-08 15:09   ` Philipp Stephani
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier @ 2017-04-05  1:09 UTC (permalink / raw)
  To: emacs-devel

> In looking at the 'record' feature recently added to master, I noticed that
> (record 'integer 'foo 'bar) returns a value V such that (type-of V) yields
> the symbol 'integer', even though V is not an integer. Is this intended?

Yes.  `record` is just a primitive on top of which we can build things
(e.g. cl-defstruct or EIEIO).

> Or should 'record' and 'make-record' reject attempts to build records
> that pretend to be of primitive types?

I don't see the benefit in trying to try hard to prevent the user from
shooting himself in the foot.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-04-05  1:09 ` Stefan Monnier
@ 2017-04-08 15:09   ` Philipp Stephani
  2017-04-08 17:57     ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Philipp Stephani @ 2017-04-08 15:09 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 423 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Mi., 5. Apr. 2017 um
03:10 Uhr:

> > Or should 'record' and 'make-record' reject attempts to build records
> > that pretend to be of primitive types?
>
> I don't see the benefit in trying to try hard to prevent the user from
> shooting himself in the foot.
>
>
It's not trying hard, just a simple check for a known, small, and
rarely-changing list of primitive symbols.

[-- Attachment #2: Type: text/html, Size: 859 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-04-08 15:09   ` Philipp Stephani
@ 2017-04-08 17:57     ` Stefan Monnier
  2017-05-01 11:35       ` Philipp Stephani
  2017-06-12 17:40       ` Stefan Monnier
  0 siblings, 2 replies; 18+ messages in thread
From: Stefan Monnier @ 2017-04-08 17:57 UTC (permalink / raw)
  To: emacs-devel

> It's not trying hard, just a simple check for a known, small, and
> rarely-changing list of primitive symbols.

To me, that's working very hard:
- extra code.
- extra maintenance
- extra run-time checks.
- no benefit since this doesn't catch a common situation.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-04-08 17:57     ` Stefan Monnier
@ 2017-05-01 11:35       ` Philipp Stephani
  2017-05-01 12:03         ` Stefan Monnier
  2017-06-12 17:40       ` Stefan Monnier
  1 sibling, 1 reply; 18+ messages in thread
From: Philipp Stephani @ 2017-05-01 11:35 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 765 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Sa., 8. Apr. 2017 um
19:58 Uhr:

> > It's not trying hard, just a simple check for a known, small, and
> > rarely-changing list of primitive symbols.
>
> To me, that's working very hard:
> - extra code.
>

Only a tiny bit.


> - extra maintenance
>

Negligible, because we rarely add new primitive types. A comment should be
added to Ftype_of to also modify a static list of primitive types when
adding a new type, but that should be it.


> - extra run-time checks.
>

Minor concern. Emacs Lisp isn't C; we prefer to help the user over saving a
couple of clock cycles.


> - no benefit since this doesn't catch a common situation.
>

Catching uncommon situation is precisely the point of precondition
checking.

[-- Attachment #2: Type: text/html, Size: 1533 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-05-01 11:35       ` Philipp Stephani
@ 2017-05-01 12:03         ` Stefan Monnier
  2017-06-10 11:39           ` Philipp Stephani
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier @ 2017-05-01 12:03 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: emacs-devel

>> - no benefit since this doesn't catch a common situation.
> Catching uncommon situation is precisely the point of precondition
> checking.

I'm talking about "common" within erroneous situations.

There is an endless supply of erroneous situations: we only bother to
try and detect those that are serious (e.g. could cause a memory
corruption) or frequent/common.

I've never seen this kind of error in the wild, so I doubt it would
*ever* prove useful to someone.


        Stefan



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-05-01 12:03         ` Stefan Monnier
@ 2017-06-10 11:39           ` Philipp Stephani
  2017-06-10 12:43             ` Eli Zaretskii
  0 siblings, 1 reply; 18+ messages in thread
From: Philipp Stephani @ 2017-06-10 11:39 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 269 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Mo., 1. Mai 2017 um
14:03 Uhr:

> we only bother to
> try and detect those that are serious (e.g. could cause a memory
> corruption) or frequent/common.
>
>
As said in another thread, I disagree with that principle.

[-- Attachment #2: Type: text/html, Size: 558 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-10 11:39           ` Philipp Stephani
@ 2017-06-10 12:43             ` Eli Zaretskii
  2017-06-12 15:07               ` Philipp Stephani
  0 siblings, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2017-06-10 12:43 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: monnier, emacs-devel

> From: Philipp Stephani <p.stephani2@gmail.com>
> Date: Sat, 10 Jun 2017 11:39:40 +0000
> Cc: emacs-devel@gnu.org
> 
> Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Mo., 1. Mai 2017 um 14:03 Uhr:
> 
>  we only bother to
>  try and detect those that are serious (e.g. could cause a memory
>  corruption) or frequent/common.
> 
> As said in another thread, I disagree with that principle. 

It's okay to disagree, but these have been the principles underlying
Emacs development since about forever, so please try to be consistent
with them as long as they are followed.  I don't think a case for
making Emacs Lisp a more restricted development environment than it is
now will gain many supporters.  E.g., even the move to make characters
a special data type separate from integers, something the XEmacs
actually did, was rejected by Emacs.

Of course, you should feel free to start a discussion about this, and
let's see how many people support your proposed direction.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-10 12:43             ` Eli Zaretskii
@ 2017-06-12 15:07               ` Philipp Stephani
  2017-06-12 17:00                 ` Eli Zaretskii
  0 siblings, 1 reply; 18+ messages in thread
From: Philipp Stephani @ 2017-06-12 15:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1124 bytes --]

Eli Zaretskii <eliz@gnu.org> schrieb am Sa., 10. Juni 2017 um 14:44 Uhr:

> > From: Philipp Stephani <p.stephani2@gmail.com>
> > Date: Sat, 10 Jun 2017 11:39:40 +0000
> > Cc: emacs-devel@gnu.org
> >
> > Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Mo., 1. Mai 2017
> um 14:03 Uhr:
> >
> >  we only bother to
> >  try and detect those that are serious (e.g. could cause a memory
> >  corruption) or frequent/common.
> >
> > As said in another thread, I disagree with that principle.
>
> It's okay to disagree, but these have been the principles underlying
> Emacs development since about forever, so please try to be consistent
> with them as long as they are followed.  I don't think a case for
> making Emacs Lisp a more restricted development environment than it is
> now will gain many supporters.  E.g., even the move to make characters
> a special data type separate from integers, something the XEmacs
> actually did, was rejected by Emacs.
>

That's not my intention. What I have in mind is to raise more signals in
cases where users use Emacs functions incorrectly instead of employing
unspecified behavior.

[-- Attachment #2: Type: text/html, Size: 1681 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-12 15:07               ` Philipp Stephani
@ 2017-06-12 17:00                 ` Eli Zaretskii
  2017-06-12 17:15                   ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2017-06-12 17:00 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: monnier, emacs-devel

> From: Philipp Stephani <p.stephani2@gmail.com>
> Date: Mon, 12 Jun 2017 15:07:16 +0000
> Cc: monnier@iro.umontreal.ca, emacs-devel@gnu.org
> 
>  It's okay to disagree, but these have been the principles underlying
>  Emacs development since about forever, so please try to be consistent
>  with them as long as they are followed. I don't think a case for
>  making Emacs Lisp a more restricted development environment than it is
>  now will gain many supporters. E.g., even the move to make characters
>  a special data type separate from integers, something the XEmacs
>  actually did, was rejected by Emacs.
> 
> That's not my intention. What I have in mind is to raise more signals in cases where users use Emacs
> functions incorrectly instead of employing unspecified behavior.

If some usage is unequivocally wrong, can never support legitimate use
cases, and the defenses are not too expensive, then I think this could
be okay.  But we need to be careful not to disallow legitimate, though
perhaps somewhat dangerous practices.  Emacs's tradition is to trust
the Lisp programmers not to shoot themselves in the foot, so we
generally prefer to err on that side of the line, when in doubt.
Punishing the innocent on behalf of possibly guilty is something I
think we should try to avoid.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-12 17:00                 ` Eli Zaretskii
@ 2017-06-12 17:15                   ` Stefan Monnier
  2017-06-12 17:22                     ` Eli Zaretskii
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier @ 2017-06-12 17:15 UTC (permalink / raw)
  To: emacs-devel

> If some usage is unequivocally wrong, can never support legitimate use
> cases, and the defenses are not too expensive, then I think this could
> be okay.  But we need to be careful not to disallow legitimate, though
> perhaps somewhat dangerous practices.  Emacs's tradition is to trust
> the Lisp programmers not to shoot themselves in the foot, so we
> generally prefer to err on that side of the line, when in doubt.
> Punishing the innocent on behalf of possibly guilty is something I
> think we should try to avoid.

I think the kind of added checks he's thinking of are "safe" in
this respect.

The reason why I disagree with them is because they are too costly
compared to the likelihood they'll ever help catch a bug (either because
they'd virtually never trigger except maybe during experimentation, and
in the unlikely event that they do trigger, the problem they discover
would quickly lead to lots of other problems anyway).

We generally don't check every imaginable meaningless circumstance, but
only those that we've found to occur often enough to warrant the runtime
and maintenance cost of an extra test.
E.g. the byte-compiler doesn't emit a warning when you try to compile
an expression like (+ 'b x).


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-12 17:15                   ` Stefan Monnier
@ 2017-06-12 17:22                     ` Eli Zaretskii
  2017-06-12 17:47                       ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2017-06-12 17:22 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Mon, 12 Jun 2017 13:15:35 -0400
> 
> > If some usage is unequivocally wrong, can never support legitimate use
> > cases, and the defenses are not too expensive, then I think this could
> > be okay.  But we need to be careful not to disallow legitimate, though
> > perhaps somewhat dangerous practices.  Emacs's tradition is to trust
> > the Lisp programmers not to shoot themselves in the foot, so we
> > generally prefer to err on that side of the line, when in doubt.
> > Punishing the innocent on behalf of possibly guilty is something I
> > think we should try to avoid.
> 
> I think the kind of added checks he's thinking of are "safe" in
> this respect.
> 
> The reason why I disagree with them is because they are too costly
> compared to the likelihood they'll ever help catch a bug

That'd be in the "defenses are too expensive" department, right?

> We generally don't check every imaginable meaningless circumstance, but
> only those that we've found to occur often enough to warrant the runtime
> and maintenance cost of an extra test.

Right.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-04-08 17:57     ` Stefan Monnier
  2017-05-01 11:35       ` Philipp Stephani
@ 2017-06-12 17:40       ` Stefan Monnier
  2017-06-16 18:42         ` Philipp Stephani
  1 sibling, 1 reply; 18+ messages in thread
From: Stefan Monnier @ 2017-06-12 17:40 UTC (permalink / raw)
  To: emacs-devel

>> It's not trying hard, just a simple check for a known, small, and
>> rarely-changing list of primitive symbols.
> To me, that's working very hard:
> - extra code.
> - extra maintenance
> - extra run-time checks.
> - no benefit since this doesn't catch a common situation.

More concretely: what would be a scenario where such a check would
be useful?

AFAICT, you need all 3 of:
1- First, you'd need someone to be foolish enough to set his record's
   type to be one of the primitive types.  This is the actual bug that
   your extra check would aim to catch.
2- Then you'd need to pass that object to a chunk of code which uses
   `type-of` and then checks the result for that primitive type.
   Otherwise, the type you set would behave just like any other
   non-primitive type so the "bug" would be harmless anyway.
3- Furthermore, you'd need this object to be manipulated exclusively in
   a way which also works with your record object without signaling an
   error (e.g. if the primitive type used is `integer`, it means your
   object should never be passed to the likes of `+` since otherwise the
   bug would already be discovered by `+` without any need for your extra
   check).

I haven't seen any evidence that step 1 will ever occur, even by accident.

No idea how likely is step 2.  `type-of` is very rarely used (except via
cl-defmethod) so it's fairly unlikely, but possible.

Step 3 seems again very unlikely in itself, and even more so if step
2 occurred: if you checked with type-of that your object is of type
`integer` there's a very high likelihood that you're going to then use
operations which only work on integers.

Will all 3 steps ever occur at the same time?

Do we really want to make every call to `make-record` pay the extra test
in order to hope to catch this hypothetical case?  Obviously I think
not, and I'd be curious to understand why you think otherwise.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-12 17:22                     ` Eli Zaretskii
@ 2017-06-12 17:47                       ` Stefan Monnier
  0 siblings, 0 replies; 18+ messages in thread
From: Stefan Monnier @ 2017-06-12 17:47 UTC (permalink / raw)
  To: emacs-devel

>> The reason why I disagree with them is because they are too costly
>> compared to the likelihood they'll ever help catch a bug
> That'd be in the "defenses are too expensive" department, right?

Right.  I just wanted to clarify that "expensive" is a relative notion:
in the case under discussion, the extra check is just a single `memq`
test on a fairly short list, so it's pretty cheap in itself; the only
reason why I find it too expensive is that the expected gain is just
extremely small.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-12 17:40       ` Stefan Monnier
@ 2017-06-16 18:42         ` Philipp Stephani
  2017-06-16 19:07           ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Philipp Stephani @ 2017-06-16 18:42 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3372 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Mo., 12. Juni 2017 um
19:41 Uhr:

> >> It's not trying hard, just a simple check for a known, small, and
> >> rarely-changing list of primitive symbols.
> > To me, that's working very hard:
> > - extra code.
> > - extra maintenance
> > - extra run-time checks.
> > - no benefit since this doesn't catch a common situation.
>
> More concretely: what would be a scenario where such a check would
> be useful?
>
> AFAICT, you need all 3 of:
> 1- First, you'd need someone to be foolish enough to set his record's
>    type to be one of the primitive types.  This is the actual bug that
>    your extra check would aim to catch.
>

Yes, though I wouldn't consider it foolish. make-record can be called
indirectly, maybe even from a function that somehow generates the type
name. People might try to create records named 'integer' and be happy that
that appears to work.


> 2- Then you'd need to pass that object to a chunk of code which uses
>    `type-of` and then checks the result for that primitive type.
>    Otherwise, the type you set would behave just like any other
>    non-primitive type so the "bug" would be harmless anyway.
> 3- Furthermore, you'd need this object to be manipulated exclusively in
>    a way which also works with your record object without signaling an
>    error (e.g. if the primitive type used is `integer`, it means your
>    object should never be passed to the likes of `+` since otherwise the
>    bug would already be discovered by `+` without any need for your extra
>    check).
>
> I haven't seen any evidence that step 1 will ever occur, even by accident.
>

I don't care about how often some bug will occur. Rather the contrary: it's
the rare bugs that are insidious. People learn about the common ones
quickly, but nobody will expect a rare bug, until it arises.


>
> No idea how likely is step 2.  `type-of` is very rarely used (except via
> cl-defmethod) so it's fairly unlikely, but possible.
>
> Step 3 seems again very unlikely in itself, and even more so if step
> 2 occurred: if you checked with type-of that your object is of type
> `integer` there's a very high likelihood that you're going to then use
> operations which only work on integers.
>
> Will all 3 steps ever occur at the same time?
>

I don't think this is an important question. The important point is:
Previously, there were invariants such as (integerp x) == (eq (type-of x)
'integer) or that prin1 would only generate #s(hash-table ...) for actual
hash tables. Now these invariants are broken. But it's critical that
invariants are never broken, no matter how unlikely the breakage is.
Imagine a system where 1 + 1 = 3 in one trillionth of the executions: even
if the bug were rare, that system would be unusable. Even worse, because it
is so rare, it is much more disastrous when it happens, because people
started relying on the invariant that is "almost" guaranteed. But there's a
discontinuity between "invariant is guaranteed" and "invariant is almost
always guaranteed": the latter is identical to "invariant is not guaranteed
at all".


>
> Do we really want to make every call to `make-record` pay the extra test
> in order to hope to catch this hypothetical case?


Yes, absolutely. I don't care whether it's rare or hypothetical, it breaks
an invariant, and invariants must not be broken.

[-- Attachment #2: Type: text/html, Size: 4403 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-16 18:42         ` Philipp Stephani
@ 2017-06-16 19:07           ` Stefan Monnier
  2017-09-24 14:47             ` Philipp Stephani
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier @ 2017-06-16 19:07 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: emacs-devel

>> Will all 3 steps ever occur at the same time?
> I don't think this is an important question.

But in the absence of the combination of those 3 steps, your check will
make no difference.  Are you saying that you don't think "whether my
check makes a difference" is an important question?

> The important point is: Previously, there were invariants such as
> (integerp x) == (eq (type-of x) 'integer) or that prin1 would only
> generate #s(hash-table ...) for actual hash tables.  Now these
> invariants are broken.

Every patch we install changes an "invariant" (except for cosmetic
patches, changes to the build system, ...).

So we can't take such an absolute position, if we want to keep
developing Emacs (including fixing bugs): we necessarily have to judge
which invariants are worthy of being preserved and which ones aren't.
E.g. if we ever get good support for bignums, we'll likely have to break
your first invariant.

Also we have to distinguish between breaking an invariant and not
enforcing it.  I do consider an Elisp code which creates a record of
type `integer` as a bug, but I don't think it's worth this particular
effort to enforce it.

Even with your extra check the above two invariants won't always hold.
I can trivially break the first one with some add-advice on type-of.
Should we add another check to prevent breaking the "invariant" in that
other way?  The second can be broken without even using an advice on
`prin1` simply by creating a record of type (make-symbol "hash-table").
Should we also add yet another check to try and avoid this other way to
break your "invariant"?

> But there's a discontinuity between "invariant is guaranteed" and
> "invariant is almost always guaranteed": the latter is identical to
> "invariant is not guaranteed at all".

In Elisp, the general rule is that thanks to the dynamic nature of the
language, there are precious few invariants which really always hold.
E.g. as soon as your "invariant" calls a function by name, you're
exposed to breakage via the advice mechanism.

So, in a sense, Elisp is a landmine just like C.

> Yes, absolutely.  I don't care whether it's rare or hypothetical, it breaks
> an invariant, and invariants must not be broken.

You might like to try Agda or Coq, but Elisp will inevitably disappoint
you in this area.

In case you're interested, my own hobby language, Typer, tries to
combine Coq with Lisp.


        Stefan



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-06-16 19:07           ` Stefan Monnier
@ 2017-09-24 14:47             ` Philipp Stephani
  2017-09-24 16:44               ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Philipp Stephani @ 2017-09-24 14:47 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 4447 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Fr., 16. Juni 2017 um
21:07 Uhr:

> >> Will all 3 steps ever occur at the same time?
> > I don't think this is an important question.
>
> But in the absence of the combination of those 3 steps, your check will
> make no difference.  Are you saying that you don't think "whether my
> check makes a difference" is an important question?
>

It does make a difference. It's important for specifications to be precise
and unsurprising, no matter whether a certain case is frequent or not.


>
> > The important point is: Previously, there were invariants such as
> > (integerp x) == (eq (type-of x) 'integer) or that prin1 would only
> > generate #s(hash-table ...) for actual hash tables.  Now these
> > invariants are broken.
>
> Every patch we install changes an "invariant" (except for cosmetic
> patches, changes to the build system, ...).
>
> So we can't take such an absolute position, if we want to keep
> developing Emacs (including fixing bugs): we necessarily have to judge
> which invariants are worthy of being preserved and which ones aren't.
>

True, but such changes need to be considered very carefully, and we need to
state explicitly which invariants can be broken without notifying anybody
(e.g. introducing new functions in the global namespace), which can be
broken by listing them in the NEWS file under "Breaking changes" (such as
removing a function), and which invariants cannot be broken.
The change being discussed here is at least in the second category. I would
argue it is even in the third category: it breaks invariants around
fundamental ELisp types for no good reason.


> E.g. if we ever get good support for bignums, we'll likely have to break
> your first invariant.
>

We can't do that. Bignum support would either have to be completely
transparent (which would make `eq' more complex), or they should be a
completely separate type.


>
> Also we have to distinguish between breaking an invariant and not
> enforcing it.  I do consider an Elisp code which creates a record of
> type `integer` as a bug, but I don't think it's worth this particular
> effort to enforce it.
>

This doesn't work: if it's not an explicit error, then people will start
relying on it ("Hyrum's law"). We need to enforce our specifications,
otherwise they aren't specifications.


>
> Even with your extra check the above two invariants won't always hold.
> I can trivially break the first one with some add-advice on type-of.
> Should we add another check to prevent breaking the "invariant" in that
> other way?  The second can be broken without even using an advice on
> `prin1` simply by creating a record of type (make-symbol "hash-table").
> Should we also add yet another check to try and avoid this other way to
> break your "invariant"?
>

No. Even though I dislike the advice functionality, would want to ban it
for primitive functions, and think that it's dangerously overused, it (or
rather the underlying `fset' primitive) is a part of the language, just
like reflection in Java. Users should definitely be warned to steer clear
from fset and its wrappers except for specialized uses such as mocking, but
its existence shouldn't affect other development: Code may always assume
that `fset' hasn't been called on any of the named functions it calls. If
that assumption is broken, it's the burden of the code that breaks it.


>
> > But there's a discontinuity between "invariant is guaranteed" and
> > "invariant is almost always guaranteed": the latter is identical to
> > "invariant is not guaranteed at all".
>
> In Elisp, the general rule is that thanks to the dynamic nature of the
> language, there are precious few invariants which really always hold.
> E.g. as soon as your "invariant" calls a function by name, you're
> exposed to breakage via the advice mechanism.
>
> So, in a sense, Elisp is a landmine just like C.
>

Most languages have escape hatches (e.g. reflection in Java). That doesn't
mean we should accept them as a given or introduce more them for no good
reason.


>
> > Yes, absolutely.  I don't care whether it's rare or hypothetical, it
> breaks
> > an invariant, and invariants must not be broken.
>
> You might like to try Agda or Coq, but Elisp will inevitably disappoint
> you in this area.
>
>
As mentioned, such invariants can be written conditionally to no `fset'
calls happening. If `fset' is used, all invariants are trivially broken.

[-- Attachment #2: Type: text/html, Size: 6051 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Should records be able to mimic primitive types?
  2017-09-24 14:47             ` Philipp Stephani
@ 2017-09-24 16:44               ` Stefan Monnier
  0 siblings, 0 replies; 18+ messages in thread
From: Stefan Monnier @ 2017-09-24 16:44 UTC (permalink / raw)
  To: emacs-devel

> As mentioned, such invariants can be written conditionally to no `fset'
> calls happening. If `fset' is used, all invariants are trivially broken.

Emacs was designed with the intention to make it easy to change pretty
much any part of its behavior.  `fset` is one of the tools for that, but
it's far from the only one.

We can't list all the ways someone can shoot himself in the foot with
Emacs Lisp, and even less automatically check them.  So we have to limit
ourselves to something more realistic, which is to focus on the problems
which do occur with some reasonable probability.

This said, if you do want to avoid such structs, I won't object (tho
I'll find it a waste of time) as long as the check is done at
compile-time (so it has 0 cost at run-time), e.g. in the
`cl-defstruct` macro.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2017-09-24 16:44 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-04 22:00 Should records be able to mimic primitive types? Paul Eggert
2017-04-05  1:09 ` Stefan Monnier
2017-04-08 15:09   ` Philipp Stephani
2017-04-08 17:57     ` Stefan Monnier
2017-05-01 11:35       ` Philipp Stephani
2017-05-01 12:03         ` Stefan Monnier
2017-06-10 11:39           ` Philipp Stephani
2017-06-10 12:43             ` Eli Zaretskii
2017-06-12 15:07               ` Philipp Stephani
2017-06-12 17:00                 ` Eli Zaretskii
2017-06-12 17:15                   ` Stefan Monnier
2017-06-12 17:22                     ` Eli Zaretskii
2017-06-12 17:47                       ` Stefan Monnier
2017-06-12 17:40       ` Stefan Monnier
2017-06-16 18:42         ` Philipp Stephani
2017-06-16 19:07           ` Stefan Monnier
2017-09-24 14:47             ` Philipp Stephani
2017-09-24 16:44               ` Stefan Monnier

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.