From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Philipp Stephani Newsgroups: gmane.emacs.devel Subject: Re: Should records be able to mimic primitive types? Date: Sun, 24 Sep 2017 14:47:56 +0000 Message-ID: References: <8777899d-ca8e-212c-b8bf-2f8da4c54836@cs.ucla.edu> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="001a113cde84ac7a2f0559f087be" X-Trace: blaine.gmane.org 1506264586 994 195.159.176.226 (24 Sep 2017 14:49:46 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 24 Sep 2017 14:49:46 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Sep 24 16:49:41 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dw8E0-0008GB-GT for ged-emacs-devel@m.gmane.org; Sun, 24 Sep 2017 16:49:40 +0200 Original-Received: from localhost ([::1]:38414 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dw8E6-0002pX-CJ for ged-emacs-devel@m.gmane.org; Sun, 24 Sep 2017 10:49:46 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:57040) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dw8CX-0002dw-Mk for emacs-devel@gnu.org; Sun, 24 Sep 2017 10:48:11 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dw8CW-0002DG-3z for emacs-devel@gnu.org; Sun, 24 Sep 2017 10:48:09 -0400 Original-Received: from mail-oi0-x22f.google.com ([2607:f8b0:4003:c06::22f]:50205) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dw8CV-0002Cg-Sq for emacs-devel@gnu.org; Sun, 24 Sep 2017 10:48:08 -0400 Original-Received: by mail-oi0-x22f.google.com with SMTP id w65so3905120oia.7 for ; Sun, 24 Sep 2017 07:48:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=2DmhFj5wITZxdQhpDz2Mk9PkJ4Ate8lve3mqm+nEdyk=; b=QxrlaLNo+VOo2k5lG8mwUxnjAqYldbBUhM3HipkamVSZ9Iq7ftvldW53QtQ0VgUrHA UKcBy9ciTZkVV8XYMFy8K3hU2HtA+1vReQo0toqMKtsTdA9dpcXkx40UYDFpt4Iwe2DX QR5dLQ6/IBC82I20/dG1bi3wasgomrQljeFi+QauuJN2IC72FXgoJAxk0B3UNpHdM8ha 6pp27L2e5We7RoT/Y+IXUPtc8Jb9W14KbbHBSDxxFHjLxAUZHw9vMJmYrIglikqywk5M X+qDKW9j3Tt/93JlWc+91CArizVTdZ383+RGQQfXccXp1JmgG9MZ1aU7ksLEhkUEaEmj eMzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=2DmhFj5wITZxdQhpDz2Mk9PkJ4Ate8lve3mqm+nEdyk=; b=pVf80HARJimgLBacQqztvEpiIg/UD+wZ9RtIyNLWeHtFmsQtyOjuN3VdxLHb+8flQw GXow87W0C0FIpWmcRRL64hIx3mdF02yzh8ylu+sjPoH7bJT2tQG9zee0d0TLPUSm6Rk3 VDaL0pGCDfDNuA4hWmuh5hlbBmYdnXrRmfauoGwklztVw3o5mCgNC0ekgEgSLPMLjcrG mb8Vo31PAQ4Z9csni8Kxh8K+5zy+N+VWHzTx49uz4VFt2N49F3AJ7OR/nKugoWkcWaG9 gHj/Tu8j/CLfjZdhlOoVV+w2uLg3mV0vgIexn87FGD8bBLAIrLvei+KQE4vecYRHGQtx iIqQ== X-Gm-Message-State: AHPjjUgD98TyM5j5phhJQMBlZ8zbAvxlSIEWGA8s4HlnytgKbgLwpAJN QX6fLsBQIorgpPQSVHCIT7YWvi2FlMFKhL8qBs4FpASt X-Google-Smtp-Source: AOwi7QAk9Zvym5N8Yqn4ymhywFJqZ1xXxTUadKQGDjZ9aj+WhRNauKUvDc2WRPMlI2oOmaGWYp1OW37Cl50Qub+XlKc= X-Received: by 10.202.57.130 with SMTP id g124mr5354098oia.296.1506264486802; Sun, 24 Sep 2017 07:48:06 -0700 (PDT) In-Reply-To: X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4003:c06::22f X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:218745 Archived-At: --001a113cde84ac7a2f0559f087be Content-Type: text/plain; charset="UTF-8" Stefan Monnier 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. --001a113cde84ac7a2f0559f087be Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


Stefan= Monnier <monnier@iro.umontr= eal.ca> schrieb am Fr., 16. Juni 2017 um 21:07=C2=A0Uhr:
>> Will all 3 steps ever occur at the sa= me 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.=C2=A0 Are you saying that you don't think "whe= ther my
check makes a difference" is an important question?

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

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

Every patch we install changes an "invariant" (except for cosmeti= c
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 consid= ered very carefully, and we need to state explicitly which invariants can b= e broken without notifying anybody (e.g. introducing new functions in the g= lobal namespace), which can be broken by listing them in the NEWS file unde= r "Breaking changes" (such as removing a function), and which inv= ariants cannot be broken.
The change being discussed here is at l= east 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.
=C2=A0
E.g. if we ever get good support for bignums, we'll likely have to brea= k
your first invariant.

We can't do t= hat. Bignum support would either have to be completely transparent (which w= ould make `eq' more complex), or they should be a completely separate t= ype.
=C2=A0

Also we have to distinguish between breaking an invariant and not
enforcing it.=C2=A0 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 particul= ar
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, ot= herwise they aren't specifications.
=C2=A0

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

No. E= ven though I dislike the advice functionality, would want to ban it for pri= mitive functions, and think that it's dangerously overused, it (or rath= er the underlying `fset' primitive) is a part of the language, just lik= e 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 t= hat `fset' hasn't been called on any of the named functions it call= s. If that assumption is broken, it's the burden of the code that break= s it.
=C2=A0

> But there's a discontinuity between "invariant is guaranteed&= quot; and
> "invariant is almost always guaranteed": the latter is ident= ical 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= 9;re
exposed to breakage via the advice mechanism.

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

<= /div>
Most languages have escape hatches (e.g. reflection in Java). Tha= t doesn't mean we should accept them as a given or introduce more them = for no good reason.
=C2=A0

> Yes, absolutely.=C2=A0 I don't care whether it's rare or hypot= hetical, 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 w= ritten conditionally to no `fset' calls happening. If `fset' is use= d, all invariants are trivially broken.=C2=A0
--001a113cde84ac7a2f0559f087be--