Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.os.vms > #378136 > unrolled thread
| Started by | Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> |
|---|---|
| First post | 2025-11-13 14:04 +0000 |
| Last post | 2025-11-21 03:03 +0000 |
| Articles | 17 on this page of 37 — 8 participants |
Back to article view | Back to comp.os.vms
Unsafe code blocks Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2025-11-13 14:04 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-13 15:44 -0500
Re: Unsafe code blocks Marc Van Dyck <marc.gr.vandyck@invalid.skynet.be> - 2025-11-14 12:14 +0100
Re: Unsafe code blocks John Reagan <johnrreagan@earthlink.net> - 2025-11-14 11:47 -0500
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-14 14:02 -0500
Re: Unsafe code blocks Marc Van Dyck <marc.gr.vandyck@invalid.skynet.be> - 2025-11-17 09:25 +0100
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-17 14:58 -0500
Re: Unsafe code blocks Chris Townley <news@cct-net.co.uk> - 2025-11-17 20:11 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-17 15:47 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-18 13:10 +0000
Re: Unsafe code blocks Lawrence D’Oliveiro <ldo@nz.invalid> - 2025-11-14 19:32 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-14 13:55 -0500
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-14 20:00 -0500
Re: Unsafe code blocks Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2025-11-17 18:56 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-17 14:22 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-16 02:16 +0000
Re: Unsafe code blocks Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2025-11-17 19:22 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-17 14:55 -0500
Re: Unsafe code blocks Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2025-11-17 20:33 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-17 15:55 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-18 12:54 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-18 14:04 -0500
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-18 14:07 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-19 16:12 +0000
Re: Unsafe code blocks Michael S <already5chosen@yahoo.com> - 2025-11-19 19:29 +0200
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-19 19:00 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-19 12:41 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-19 18:19 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-19 14:21 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-19 19:49 +0000
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-19 16:02 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-19 20:26 -0500
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-19 20:31 -0500
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-19 21:32 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-20 11:54 +0000
Re: Unsafe code blocks Arne Vajhøj <arne@vajhoej.dk> - 2025-11-20 19:18 -0500
Re: Unsafe code blocks cross@spitfire.i.gajendra.net (Dan Cross) - 2025-11-21 03:03 +0000
Page 2 of 2 — ← Prev page 1 [2]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-18 12:54 +0000 |
| Message-ID | <10fhqao$gt4$1@reader2.panix.com> |
| In reply to | #378168 |
In article <10ffsku$1233b$2@dont-email.me>,
Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote:
>On 2025-11-15, Dan Cross <cross@spitfire.i.gajendra.net> wrote:
>> In article <10f4oi1$25lkk$2@dont-email.me>,
>> Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote:
>>>
>>>The unsafe keyword is a hack implemented in languages that have not been
>>>designed correctly.
>>
>> Wait, Simon, tell me how you really feel.
>>
>
>Well, Simon is known to have opinions. :-)
:-D
>>>The Ada approach, of disabling checks on a specific
>>>reference to a variable instead of disabling checks within a whole block
>>>of code, is far superior.
>>
>> It's unclear to me how this is materially different.
>>
>> In Rust, blocks return the value of the last expression they
>> contain, so an `unsafe` block may refer to a single expression.
>> However, I disagree with the above in the sense that the ability
>> to introduce scope when doing something `unsafe` can be
>> incredibly useful. But what if the expression is really a
>> statement?
>>
>> For example:
>>
>> ```rust
>> unsafe {
>> use core::intrinsics::volatile_copy_memory;
>> let src = entry.virt_page_addr() as *const arch::Page;
>> volatile_copy_memory(page, src, 1);
>> }
>> ```
>
>And that is exactly the kind of thing I am talking about. :-)
>
>Of those three statements, only the last one appears to be the unsafe one.
This is true, but also the sort of thing where I want to
localize the scope of both the use statement, as well as `src`.
>It is also the kind of thing I was reacting to when I saw Arne's
>example and went YUCK!, YUCK!, YUCK! :-)
Heh.
>> There's no need to leak the existence of `src` or that one is
>> using the volatile memcpy intrinsic here. I suppose could could
>> also write this as,
>
>If that is important, I would have placed the whole sequence inside a
>local block as you do below.
>
>> ```rust
>> {
>> use core::intrinsics::volatile_copy_memory;
>> let src = entry.virt_page_addr() as *const arch::Page;
>> unsafe {
>> volatile_copy_memory(page, src, 1);
>> }
>> }
>> ```
>
>And this example is much closer to the Ada way. Related statements still
>get checked and only one specific statement, the actual statement that is
>unsafe, has checks disabled.
Let me be clear: _all_ of those expressions get checked. The
`unsafe` superset just lets you do a few additional things; the
contract is that you, the programmer, have some external domain
knowledge that the compiler cannot derive from the code, and you
are asserting that you have verified that the language's
requirements vis its semantics hold, since the compiler cannot
check that for you. `unsafe` does not mean you get to violate
the language's rules; it just means that you're taking
responsibility for them when the compiler would ordinarily do
that for you.
>> etc.
>>
>>
>>>For example, this is how you do an unsafe conversion in Ada:
>>>
>>>https://adaic.org/resources/add_content/docs/95style/html/sec_5/5-9-1.html
>>
>> This example seems equivalent to an `unsafe fn` in Rust. An
>> unsafe conversion of this nature might use `std::mem::transmute`
>> in that world.
>
>The Ada example localises the unsafe bit down to a specific operation
>within a statement, not a full statement, and certainly not a full function.
Ah, I'm being unclear, then. In Rust, `unsafe fn` means that
the function must be _called_ from an `unsafe` block. It does
not mean that the statements inside the function are implicitly
wrapped in an `unsafe` block (though in fairness it used to;
this was changed in, I believe, the 2024 edition of the
language).
Anyway, I think it's unfair to say that `unsafe` blocks are a
misfeature, or a sign of poor design. In expression-oriented
languages, they're sort of size-to-fit.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-18 14:04 -0500 |
| Message-ID | <10fig0p$1n41a$2@dont-email.me> |
| In reply to | #378165 |
On 11/15/2025 9:16 PM, Dan Cross wrote:
>> Also note the availability of the 'Valid attribute to make sure that what
>> is in the variable after the unsafe conversion is actually a valid value.
>
> Sum types make this trivial:
>
> impl SomeType {
> fn try_from(i: i32) -> Option<Self> {
> // if valid, return `Some(whatever`),
> // else return `None`.
> }
> }
(assuming Option in Rust is what it is in other languages)
Option and Ada Valid are somewhat different.
Option is a way for a function/method to either return
a value or return the fact that there is no value.
A much better way to do that than traditional
return null or -1 or whatever to indicate there
is no value.
Ada valid attribute is a runtime check on the result from
an unsafe conversion to see if it meets the constraints
of the data type.
Arne
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-18 14:07 -0500 |
| Message-ID | <10fig54$1n41a$3@dont-email.me> |
| In reply to | #378185 |
On 11/18/2025 2:04 PM, Arne Vajhøj wrote:
> On 11/15/2025 9:16 PM, Dan Cross wrote:
>>> Also note the availability of the 'Valid attribute to make sure that
>>> what
>>> is in the variable after the unsafe conversion is actually a valid
>>> value.
>>
>> Sum types make this trivial:
>>
>> impl SomeType {
>> fn try_from(i: i32) -> Option<Self> {
>> // if valid, return `Some(whatever`),
>> // else return `None`.
>> }
>> }
> (assuming Option in Rust is what it is in other languages)
>
> Option and Ada Valid are somewhat different.
>
> Option is a way for a function/method to either return
> a value or return the fact that there is no value.
>
> A much better way to do that than traditional
> return null or -1 or whatever to indicate there
> is no value.
>
> Ada valid attribute is a runtime check on the result from
> an unsafe conversion to see if it meets the constraints
> of the data type.
Option is in fashion in recent years.
There are not that many languages on VMS supporting
Option.
Scala does - Option[T].
And Java 8 Optional<T> is almost the same.
Arne
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-19 16:12 +0000 |
| Message-ID | <10fkq9g$8f$1@reader2.panix.com> |
| In reply to | #378186 |
In article <10fig54$1n41a$3@dont-email.me>,
Arne Vajhøj <arne@vajhoej.dk> wrote:
>On 11/18/2025 2:04 PM, Arne Vajhøj wrote:
>> On 11/15/2025 9:16 PM, Dan Cross wrote:
>>>> Also note the availability of the 'Valid attribute to make sure that
>>>> what
>>>> is in the variable after the unsafe conversion is actually a valid
>>>> value.
>>>
>>> Sum types make this trivial:
>>>
>>> impl SomeType {
>>> fn try_from(i: i32) -> Option<Self> {
>>> // if valid, return `Some(whatever`),
>>> // else return `None`.
>>> }
>>> }
>> (assuming Option in Rust is what it is in other languages)
>>
>> Option and Ada Valid are somewhat different.
>>
>> Option is a way for a function/method to either return
>> a value or return the fact that there is no value.
>>
>> A much better way to do that than traditional
>> return null or -1 or whatever to indicate there
>> is no value.
>>
>> Ada valid attribute is a runtime check on the result from
>> an unsafe conversion to see if it meets the constraints
>> of the data type.
>
>Option is in fashion in recent years.
Algebraic data types have been used in functional languages
since the 1970s, starting with the "Hope" language from
Edinburgh. ML took them from Hope and popularized them, and
they leaked into Miranda, Haskell, and OCaml from there. Now
many languages support them; even C++ (`std::optional`).
Hope was first described in a paper in 1980, but the work of
course predated that.
That makes them about as old as VMS, and older than Ada. In
other words, they've been "In Fashion" since the 70s, which as
far as all things fashion goes, is a pretty good run;
particularly considering some of the things that were popular in
that decade.
>There are not that many languages on VMS supporting
>Option.
>
>Scala does - Option[T].
>
>And Java 8 Optional<T> is almost the same.
More's the pity.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-19 19:29 +0200 |
| Message-ID | <20251119192953.00005981@yahoo.com> |
| In reply to | #378188 |
On Wed, 19 Nov 2025 16:12:32 -0000 (UTC)
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
> In article <10fig54$1n41a$3@dont-email.me>,
> Arne Vajh_¸j <arne@vajhoej.dk> wrote:
> >On 11/18/2025 2:04 PM, Arne Vajh_¸j wrote:
> >> On 11/15/2025 9:16 PM, Dan Cross wrote:
> >>>> Also note the availability of the 'Valid attribute to make sure
> >>>> that what
> >>>> is in the variable after the unsafe conversion is actually a
> >>>> valid value.
> >>>
> >>> Sum types make this trivial:
> >>>
> >>> _ _ _ _ impl SomeType {
> >>> _ _ _ _ _ _ _ _ fn try_from(i: i32) -> Option<Self> {
> >>> _ _ _ _ _ _ _ _ _ _ _ _ // if valid, return `Some(whatever`),
> >>> _ _ _ _ _ _ _ _ _ _ _ _ // else return `None`.
> >>> _ _ _ _ _ _ _ _ }
> >>> _ _ _ _ }
> >> (assuming Option in Rust is what it is in other languages)
> >>
> >> Option and Ada Valid are somewhat different.
> >>
> >> Option is a way for a function/method to either return
> >> a value or return the fact that there is no value.
> >>
> >> A much better way to do that than traditional
> >> return null or -1 or whatever to indicate there
> >> is no value.
> >>
> >> Ada valid attribute is a runtime check on the result from
> >> an unsafe conversion to see if it meets the constraints
> >> of the data type.
> >
> >Option is in fashion in recent years.
>
> Algebraic data types have been used in functional languages
> since the 1970s, starting with the "Hope" language from
> Edinburgh. ML took them from Hope and popularized them, and
> they leaked into Miranda, Haskell, and OCaml from there. Now
> many languages support them; even C++ (`std::optional`).
>
> Hope was first described in a paper in 1980, but the work of
> course predated that.
>
> That makes them about as old as VMS, and older than Ada. In
> other words, they've been "In Fashion" since the 70s,
That does not follow.
Something existing for a long time is not the same as being fashionable
for a long time.
Options became fashionable relatively recently, as result of growing
dissatisfaction with previous fashionable item - exceptions.
Parts of programming community that are less concerned with fashion of
the day ignored both of this things. They use error codes, either in
crude form (like C) or more refined (like Go).
> which as
> far as all things fashion goes, is a pretty good run;
> particularly considering some of the things that were popular in
> that decade.
>
> >There are not that many languages on VMS supporting
> >Option.
> >
> >Scala does - Option[T].
> >
> >And Java 8 Optional<T> is almost the same.
>
> More's the pity.
>
> - Dan C.
>
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-19 19:00 +0000 |
| Message-ID | <10fl450$q2$1@reader2.panix.com> |
| In reply to | #378189 |
In article <20251119192953.00005981@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
>On Wed, 19 Nov 2025 16:12:32 -0000 (UTC)
>cross@spitfire.i.gajendra.net (Dan Cross) wrote:
>
>> In article <10fig54$1n41a$3@dont-email.me>,
>> Arne Vajh_¸j <arne@vajhoej.dk> wrote:
>> >On 11/18/2025 2:04 PM, Arne Vajh_¸j wrote:
>> >> On 11/15/2025 9:16 PM, Dan Cross wrote:
>> >>>> Also note the availability of the 'Valid attribute to make sure
>> >>>> that what
>> >>>> is in the variable after the unsafe conversion is actually a
>> >>>> valid value.
>> >>>
>> >>> Sum types make this trivial:
>> >>>
>> >>> _ _ _ _ impl SomeType {
>> >>> _ _ _ _ _ _ _ _ fn try_from(i: i32) -> Option<Self> {
>> >>> _ _ _ _ _ _ _ _ _ _ _ _ // if valid, return `Some(whatever`),
>> >>> _ _ _ _ _ _ _ _ _ _ _ _ // else return `None`.
>> >>> _ _ _ _ _ _ _ _ }
>> >>> _ _ _ _ }
>> >> (assuming Option in Rust is what it is in other languages)
>> >>
>> >> Option and Ada Valid are somewhat different.
>> >>
>> >> Option is a way for a function/method to either return
>> >> a value or return the fact that there is no value.
>> >>
>> >> A much better way to do that than traditional
>> >> return null or -1 or whatever to indicate there
>> >> is no value.
>> >>
>> >> Ada valid attribute is a runtime check on the result from
>> >> an unsafe conversion to see if it meets the constraints
>> >> of the data type.
>> >
>> >Option is in fashion in recent years.
>>
>> Algebraic data types have been used in functional languages
>> since the 1970s, starting with the "Hope" language from
>> Edinburgh. ML took them from Hope and popularized them, and
>> they leaked into Miranda, Haskell, and OCaml from there. Now
>> many languages support them; even C++ (`std::optional`).
>>
>> Hope was first described in a paper in 1980, but the work of
>> course predated that.
>>
>> That makes them about as old as VMS, and older than Ada. In
>> other words, they've been "In Fashion" since the 70s,
>
>That does not follow.
>Something existing for a long time is not the same as being fashionable
>for a long time.
That's a fair point, but it's also context dependent. ADTs have
been fashionable for a while in some communities, though perhaps
not in others. It depends on what kind of work you're doing and
what specific technologies you work with.
>Options became fashionable relatively recently, as result of growing
>dissatisfaction with previous fashionable item - exceptions.
Eh, now _this_ does not follow. Options and exceptions are
orthogonal, and many languages that support one also support the
other.
>Parts of programming community that are less concerned with fashion of
>the day ignored both of this things. They use error codes, either in
>crude form (like C) or more refined (like Go).
C predates ADTs, of course, and likely wouldn't have adopted
them even if it didn't because of the constraints of its early
environment.
The situation with Go is a bit more complex, and in part comes
from not designing the language with support for generics from
the start (to really make effective use of ADTs, you pretty much
need parametric polymorphism over data types), and generics were
omitted because they weren't initially sure how to make them
work well with interfaces, which they were pretty bullish on.
But I would argue that the Go convention of returning a tuple
with an explicit `error` element and allowing a simple statement
to be nested beween the `if` and boolean expression, is closer
to a Maybe monad than C's overloading an `int`, or using one a
return value in combination with an out parameter or something
similar.
- Dna C.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-19 12:41 -0500 |
| Message-ID | <10fkvfr$2d2kr$1@dont-email.me> |
| In reply to | #378188 |
On 11/19/2025 11:12 AM, Dan Cross wrote: > In article <10fig54$1n41a$3@dont-email.me>, > Arne Vajhøj <arne@vajhoej.dk> wrote: >> Option is in fashion in recent years. > > Algebraic data types have been used in functional languages > since the 1970s, starting with the "Hope" language from > Edinburgh. ML took them from Hope and popularized them, and > they leaked into Miranda, Haskell, and OCaml from there. Now > many languages support them; even C++ (`std::optional`). > > Hope was first described in a paper in 1980, but the work of > course predated that. > > That makes them about as old as VMS, and older than Ada. In > other words, they've been "In Fashion" since the 70s, which as > far as all things fashion goes, is a pretty good run; > particularly considering some of the things that were popular in > that decade. I would not consider Haskell, OCaml to ever have been in fashion. Scala 2.0 in 2006, Rust in 2012, Swift in 2014, Java 8 in 2014, Python 3.5 in 2015 (only type hint!), C++ 17 are more mainstream and more recent. Arne
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-19 18:19 +0000 |
| Message-ID | <10fl1n1$o5v$1@reader2.panix.com> |
| In reply to | #378190 |
In article <10fkvfr$2d2kr$1@dont-email.me>, Arne Vajhøj <arne@vajhoej.dk> wrote: >On 11/19/2025 11:12 AM, Dan Cross wrote: >> In article <10fig54$1n41a$3@dont-email.me>, >> Arne Vajhøj <arne@vajhoej.dk> wrote: >>> Option is in fashion in recent years. >> >> Algebraic data types have been used in functional languages >> since the 1970s, starting with the "Hope" language from >> Edinburgh. ML took them from Hope and popularized them, and >> they leaked into Miranda, Haskell, and OCaml from there. Now >> many languages support them; even C++ (`std::optional`). >> >> Hope was first described in a paper in 1980, but the work of >> course predated that. >> >> That makes them about as old as VMS, and older than Ada. In >> other words, they've been "In Fashion" since the 70s, which as >> far as all things fashion goes, is a pretty good run; >> particularly considering some of the things that were popular in >> that decade. > >I would not consider Haskell, OCaml to ever have been in fashion. In your world of business software programming? That's probably true. In the world of research and systems? Definitely not true. But notably, Haskell and OCaml both significantly post date SML. >Scala 2.0 in 2006, Rust in 2012, Swift in 2014, Java 8 in 2014, >Python 3.5 in 2015 (only type hint!), C++ 17 are more mainstream >and more recent. ...and where do you think they got the idea from? ;-} - Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-19 14:21 -0500 |
| Message-ID | <10fl5b7$2d2kq$1@dont-email.me> |
| In reply to | #378191 |
On 11/19/2025 1:19 PM, Dan Cross wrote: > In article <10fkvfr$2d2kr$1@dont-email.me>, > Arne Vajhøj <arne@vajhoej.dk> wrote: >> On 11/19/2025 11:12 AM, Dan Cross wrote: >>> In article <10fig54$1n41a$3@dont-email.me>, >>> Arne Vajhøj <arne@vajhoej.dk> wrote: >>>> Option is in fashion in recent years. >>> >>> Algebraic data types have been used in functional languages >>> since the 1970s, starting with the "Hope" language from >>> Edinburgh. ML took them from Hope and popularized them, and >>> they leaked into Miranda, Haskell, and OCaml from there. Now >>> many languages support them; even C++ (`std::optional`). >>> >>> Hope was first described in a paper in 1980, but the work of >>> course predated that. >>> >>> That makes them about as old as VMS, and older than Ada. In >>> other words, they've been "In Fashion" since the 70s, which as >>> far as all things fashion goes, is a pretty good run; >>> particularly considering some of the things that were popular in >>> that decade. >> >> I would not consider Haskell, OCaml to ever have been in fashion. > > In your world of business software programming? That's probably > true. In the world of research and systems? Definitely not > true. Hmm. I would say that the main area for Haskell and OCampl outside of university CS departments is in finance, which is business software. Just still just a niche in those companies overall IT landscape. Arne
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-19 19:49 +0000 |
| Message-ID | <10fl70e$gua$1@reader2.panix.com> |
| In reply to | #378193 |
In article <10fl5b7$2d2kq$1@dont-email.me>, Arne Vajhøj <arne@vajhoej.dk> wrote: >On 11/19/2025 1:19 PM, Dan Cross wrote: >> In article <10fkvfr$2d2kr$1@dont-email.me>, >> Arne Vajhøj <arne@vajhoej.dk> wrote: >>> On 11/19/2025 11:12 AM, Dan Cross wrote: >>>> In article <10fig54$1n41a$3@dont-email.me>, >>>> Arne Vajhøj <arne@vajhoej.dk> wrote: >>>>> Option is in fashion in recent years. >>>> >>>> Algebraic data types have been used in functional languages >>>> since the 1970s, starting with the "Hope" language from >>>> Edinburgh. ML took them from Hope and popularized them, and >>>> they leaked into Miranda, Haskell, and OCaml from there. Now >>>> many languages support them; even C++ (`std::optional`). >>>> >>>> Hope was first described in a paper in 1980, but the work of >>>> course predated that. >>>> >>>> That makes them about as old as VMS, and older than Ada. In >>>> other words, they've been "In Fashion" since the 70s, which as >>>> far as all things fashion goes, is a pretty good run; >>>> particularly considering some of the things that were popular in >>>> that decade. >>> >>> I would not consider Haskell, OCaml to ever have been in fashion. >> >> In your world of business software programming? That's probably >> true. In the world of research and systems? Definitely not >> true. > >Hmm. > >I would say that the main area for Haskell and OCampl outside of >university CS departments is in finance, which is business software. Funny, I would say compiler development and hardware design (e.g Bluespec). The only finance folks I know of using e.g. OCaml are Jane St; dunno about Haskell in that world, though Meta was using it for their PHP compiler at one point. Perhaps I should have said "enterprise software." The point is that you aren't going to see a lot of IT folks who are used to Java or C# or COBOL or something similar slinging OCaml or Haskell around. Not many of them are writing compilers either, though. >Just still just a niche in those companies overall IT landscape. I mean, Jane St uses OCaml for pretty much everything, but ok. https://www.janestreet.com/tech-talks/ocaml-all-the-way-down/ Anyway, how about getting back to the point re: Ada and `Valid`? - Dan C.
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-19 16:02 +0000 |
| Message-ID | <10fkpme$1dj$1@reader2.panix.com> |
| In reply to | #378185 |
In article <10fig0p$1n41a$2@dont-email.me>,
Arne Vajhøj <arne@vajhoej.dk> wrote:
>On 11/15/2025 9:16 PM, Dan Cross wrote:
>>> Also note the availability of the 'Valid attribute to make sure that what
>>> is in the variable after the unsafe conversion is actually a valid value.
>>
>> Sum types make this trivial:
>>
>> impl SomeType {
>> fn try_from(i: i32) -> Option<Self> {
>> // if valid, return `Some(whatever`),
>> // else return `None`.
>> }
>> }
>(assuming Option in Rust is what it is in other languages)
>
>Option and Ada Valid are somewhat different.
>
>Option is a way for a function/method to either return
>a value or return the fact that there is no value.
>
>A much better way to do that than traditional
>return null or -1 or whatever to indicate there
>is no value.
>
>Ada valid attribute is a runtime check on the result from
>an unsafe conversion to see if it meets the constraints
>of the data type.
I'm afraid this misses the point.
If a language supports sum types, then general solutions like
`Option` or `Result` types can be employed to represent the
return type of the conversion operation. If the conversion is
invalid, then one returns `None` (or, perhaps, the `Err` variant
of a `Result` if one wants to capture what the actual failure
was). That is, the conversion operation itself subsumes the
functionality of the valid attribute, and both the value and
whether the conversion was valid are represented in the return
type.
Again, taking Rust just as an example, there is a standard way
to represent such conversions; the `TryFrom` trait (and it's
dual, `TryInto`). Consider this silly example problem: I have a
type representing colors; perhaps the only colors I care about
are Red, Green, and Blue. I can label these with integers, say
1, 2 and 3, and I can represent this in Rust using an
enumeration.
Now further suppose that I have a file of 8-bit bytes that
contain the (raw, integral) representation of these color
values; I'd like to convert these into proper objects of the
enumeration type, but of course, not all 8-bit byte values
represent valid colors, so the proper tool in this case is
`TryFrom`. Note, however, that converting back, from a color to
its 8-bit value, is _always_ valid, so I just use `From` in that
case (which also, conveniently, gives me `into`).
Here's the code:
```rust
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Colors {
Red = 1,
Green = 2,
Blue = 3,
}
impl TryFrom<u8> for Colors {
type Error = String;
fn try_from(raw: u8) -> Result<Self, Self::Error> {
match raw {
1 => Ok(Self::Red),
2 => Ok(Self::Green),
3 => Ok(Self::Blue),
_ => Err(format!("unsupported value '{raw}'")),
}
}
}
impl From<Colors> for u8 {
fn from(color: Colors) -> u8 {
color as u8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn try_from_raw() {
assert_eq!(Colors::try_from(1), Ok(Colors::Red));
assert_eq!(Colors::try_from(2), Ok(Colors::Green));
assert_eq!(Colors::try_from(3), Ok(Colors::Blue));
assert_eq!(Colors::try_from(0), Err("unsupported value '0'".into()));
}
#[test]
fn from_clor() {
assert_eq!(u8::from(Colors::Red), 1);
assert_eq!(u8::from(Colors::Green), 2);
assert_eq!(u8::from(Colors::Blue), 3);
}
}
```
Note the unit tests. Note also, that, as a result of the way
that the conversion is structured, as aided by the return type,
the conversion operation itself is safe.
Of course, this example is trivial, but the same principle
applies for more comple conversions as well, including unsafe
conversions.
Further, by localizing the unsafety inside of the conversion,
and using a return type that can represent failure, one can
construct a _safe_ interface to do _unsafe_ conversions.
Consider a hypothetical in-place conversion from an array of
bytes to a string type that is guaranteed to contain only valid
UTF-8 sequences, such as a Rust `&str`. This is an `unsafe`
operation, since it relies on the program to assert that the
byte array contents are valid UTF-8. But, my conversion
function can probe the input byte sequence for validity, and
return `Err` if an invalid sequence is found, otherwise it can
do an (unsafe) conversion and return that in an `Ok`. This is
fine, since the conversion function itself enforces the
invariants required by the type.
In contrast, `Valid` is easy to misuse, primarily by not using
it at all, in which case you run the risk of raising a runtime
exception, or just having an incorrect program. With either
`Option` or `Result`, you are forced to contend with the error
case. The programmer can't forget to check.
Finally, `Valid` is very limited in its applicability: it can
only be used with scalar types. At least in Rust, `Option` and
`Result` are generic over essentially arbitrary types.
Put another way, if the language supports something like an
`Option` type, then there is no need for a special-case facility
like Ada's `Valid` attribute.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-19 20:26 -0500 |
| Message-ID | <10flqou$2l1qc$1@dont-email.me> |
| In reply to | #378187 |
On 11/19/2025 11:02 AM, Dan Cross wrote:
> In article <10fig0p$1n41a$2@dont-email.me>,
> Arne Vajhøj <arne@vajhoej.dk> wrote:
>> On 11/15/2025 9:16 PM, Dan Cross wrote:
>>>> Also note the availability of the 'Valid attribute to make sure that what
>>>> is in the variable after the unsafe conversion is actually a valid value.
>>>
>>> Sum types make this trivial:
>>>
>>> impl SomeType {
>>> fn try_from(i: i32) -> Option<Self> {
>>> // if valid, return `Some(whatever`),
>>> // else return `None`.
>>> }
>>> }
>> (assuming Option in Rust is what it is in other languages)
>>
>> Option and Ada Valid are somewhat different.
>>
>> Option is a way for a function/method to either return
>> a value or return the fact that there is no value.
>>
>> A much better way to do that than traditional
>> return null or -1 or whatever to indicate there
>> is no value.
>>
>> Ada valid attribute is a runtime check on the result from
>> an unsafe conversion to see if it meets the constraints
>> of the data type.
>
> I'm afraid this misses the point.
>
> If a language supports sum types, then general solutions like
> `Option` or `Result` types can be employed to represent the
> return type of the conversion operation. If the conversion is
> invalid, then one returns `None` (or, perhaps, the `Err` variant
> of a `Result` if one wants to capture what the actual failure
> was). That is, the conversion operation itself subsumes the
> functionality of the valid attribute, and both the value and
> whether the conversion was valid are represented in the return
> type.
>
> Again, taking Rust just as an example, there is a standard way
> to represent such conversions; the `TryFrom` trait (and it's
> dual, `TryInto`). Consider this silly example problem: I have a
> type representing colors; perhaps the only colors I care about
> are Red, Green, and Blue. I can label these with integers, say
> 1, 2 and 3, and I can represent this in Rust using an
> enumeration.
>
> Now further suppose that I have a file of 8-bit bytes that
> contain the (raw, integral) representation of these color
> values; I'd like to convert these into proper objects of the
> enumeration type, but of course, not all 8-bit byte values
> represent valid colors, so the proper tool in this case is
> `TryFrom`. Note, however, that converting back, from a color to
> its 8-bit value, is _always_ valid, so I just use `From` in that
> case (which also, conveniently, gives me `into`).
> #[derive(Clone, Copy, Debug, Eq, PartialEq)]
> enum Colors {
> Red = 1,
> Green = 2,
> Blue = 3,
> }
>
> impl TryFrom<u8> for Colors {
> type Error = String;
> fn try_from(raw: u8) -> Result<Self, Self::Error> {
> match raw {
> 1 => Ok(Self::Red),
> 2 => Ok(Self::Green),
> 3 => Ok(Self::Blue),
> _ => Err(format!("unsupported value '{raw}'")),
> }
> }
> }
> Note the unit tests. Note also, that, as a result of the way
> that the conversion is structured, as aided by the return type,
> the conversion operation itself is safe.
>
> Of course, this example is trivial, but the same principle
> applies for more comple conversions as well, including unsafe
> conversions.
>
> Further, by localizing the unsafety inside of the conversion,
> and using a return type that can represent failure, one can
> construct a _safe_ interface to do _unsafe_ conversions.
> In contrast, `Valid` is easy to misuse, primarily by not using
> it at all, in which case you run the risk of raising a runtime
> exception, or just having an incorrect program. With either
> `Option` or `Result`, you are forced to contend with the error
> case. The programmer can't forget to check.
>
> Finally, `Valid` is very limited in its applicability: it can
> only be used with scalar types. At least in Rust, `Option` and
> `Result` are generic over essentially arbitrary types.
>
> Put another way, if the language supports something like an
> `Option` type, then there is no need for a special-case facility
> like Ada's `Valid` attribute.
All fine.
But you can do the same in Ada.
Both doing similar to above and by using Unchecked_Conversion
and Valid.
with Unchecked_Conversion;
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
Procedure ColorFul is
type Color is (Red, Green, Blue);
for Color use (Red => 1, Green => 2, Blue => 3);
for Color'Size use Integer'Size;
procedure Put(col : Color) is
begin
case col is
when Red => Put("Red");
when Green => Put("Green");
when Blue => Put("Blue");
end case;
end Put;
type ColorOption(Valid : Boolean := False) is record
case Valid is
when False =>
null;
when True =>
Value : Color;
end case;
end record;
function Integer2ColorNice(I : Integer) return ColorOption is
res : ColorOption;
begin
case I is
when 1 => res := (Valid => True, Value => Red);
when 2 => res := (Valid => True, Value => Green);
when 3 => res := (Valid => True, Value => Blue);
when others => res := (Valid => False);
end case;
return res;
end Integer2ColorNice;
function Integer2ColorTricky(I : Integer) return ColorOption is
function BitI2C is new Unchecked_Conversion(Source => Integer, Target =>
Color);
temp : Color;
res : ColorOption;
begin
temp := BitI2C(I);
if temp'Valid then
res := (Valid => True, Value => temp);
else
res := (Valid => False);
end if;
return res;
end Integer2ColorTricky;
col : ColorOption;
begin
for I in 0..4 loop
col := Integer2ColorNice(I);
Put(I, Width => 1);
Put(" is ");
if col.Valid then
Put(col.Value);
else
Put("not a valid color");
end if;
New_Line;
end loop;
for I in 0..4 loop
col := Integer2ColorTricky(I);
Put(I, Width => 1);
Put(" is ");
if col.Valid then
Put(col.Value);
else
Put("not a valid color");
end if;
New_Line;
end loop;
end ColorFul;
A bit verbose. But if one want short code, then
Ada is not the right language choice.
I am printing instead of asserting, because assertions was first
to Ada 20 years ago and the VMS GNAT I have is over 25 years old.
Arne
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-19 20:31 -0500 |
| Message-ID | <10flr0n$2l1qc$2@dont-email.me> |
| In reply to | #378195 |
On 11/19/2025 8:26 PM, Arne Vajhøj wrote:
> temp := BitI2C(I);
> if temp'Valid then
> res := (Valid => True, Value => temp);
> else
> res := (Valid => False);
> end if;
> return res;
And in case someone was thinking:
temp := BitI2C(I);
res := (Valid => Temp'Valid, Value => temp);
return res;
No - that does not compile.
Arne
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-19 21:32 -0500 |
| Message-ID | <691e7dd0$0$677$14726298@news.sunsite.dk> |
| In reply to | #378195 |
On 11/19/2025 8:26 PM, Arne Vajhøj wrote:
> But you can do the same in Ada.
>
> Both doing similar to above and by using Unchecked_Conversion
> and Valid.
> Procedure ColorFul is
Maybe this variant is more Option'esque:
with Unchecked_Conversion;
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
Procedure ColorFul2 is
type Color is (Red, Green, Blue);
for Color use (Red => 1, Green => 2, Blue => 3);
for Color'Size use Integer'Size;
procedure Put(col : Color) is
begin
case col is
when Red => Put("Red");
when Green => Put("Green");
when Blue => Put("Blue");
end case;
end Put;
type ColorOption(Valid : Boolean := False) is record
case Valid is
when False =>
null;
when True =>
Value : Color;
end case;
end record;
function ColorSome(col : Color) return ColorOption is
res : ColorOption;
begin
res := (Valid => True, Value => col);
return res;
end ColorSome;
function ColorNone return ColorOption is
res : ColorOption;
begin
res := (Valid => False);
return res;
end ColorNone;
function Integer2ColorNice(I : Integer) return ColorOption is
res : ColorOption;
begin
case I is
when 1 => res := ColorSome(Red);
when 2 => res := ColorSome(Green);
when 3 => res := ColorSome(Blue);
when others => res := ColorNone;
end case;
return res;
end Integer2ColorNice;
function Integer2ColorTricky(I : Integer) return ColorOption is
function BitI2C is new Unchecked_Conversion(Source => Integer, Target =>
Color);
temp : Color;
res : ColorOption;
begin
temp := BitI2C(I);
if temp'Valid then
res := ColorSome(temp);
else
res := ColorNone;
end if;
return res;
end Integer2ColorTricky;
col : ColorOption;
begin
for I in 0..4 loop
col := Integer2ColorNice(I);
Put(I, Width => 1);
Put(" is ");
if col.Valid then
Put(col.Value);
else
Put("not a valid color");
end if;
New_Line;
end loop;
for I in 0..4 loop
col := Integer2ColorTricky(I);
Put(I, Width => 1);
Put(" is ");
if col.Valid then
Put(col.Value);
else
Put("not a valid color");
end if;
New_Line;
end loop;
end ColorFul2;
Arne
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-20 11:54 +0000 |
| Message-ID | <10fmvhp$col$1@reader2.panix.com> |
| In reply to | #378195 |
In article <10flqou$2l1qc$1@dont-email.me>,
Arne Vajhøj <arne@vajhoej.dk> wrote:
>On 11/19/2025 11:02 AM, Dan Cross wrote:
>> In article <10fig0p$1n41a$2@dont-email.me>,
>> Arne Vajhøj <arne@vajhoej.dk> wrote:
>>> On 11/15/2025 9:16 PM, Dan Cross wrote:
>>>>> Also note the availability of the 'Valid attribute to make sure that what
>>>>> is in the variable after the unsafe conversion is actually a valid value.
>>>>
>>>> Sum types make this trivial:
>>>>
>>>> impl SomeType {
>>>> fn try_from(i: i32) -> Option<Self> {
>>>> // if valid, return `Some(whatever`),
>>>> // else return `None`.
>>>> }
>>>> }
>>> (assuming Option in Rust is what it is in other languages)
>>>
>>> Option and Ada Valid are somewhat different.
>>>
>>> Option is a way for a function/method to either return
>>> a value or return the fact that there is no value.
>>>
>>> A much better way to do that than traditional
>>> return null or -1 or whatever to indicate there
>>> is no value.
>>>
>>> Ada valid attribute is a runtime check on the result from
>>> an unsafe conversion to see if it meets the constraints
>>> of the data type.
>>
>> I'm afraid this misses the point.
>>
>> If a language supports sum types, then general solutions like
>> `Option` or `Result` types can be employed to represent the
>> return type of the conversion operation. If the conversion is
>> invalid, then one returns `None` (or, perhaps, the `Err` variant
>> of a `Result` if one wants to capture what the actual failure
>> was). That is, the conversion operation itself subsumes the
>> functionality of the valid attribute, and both the value and
>> whether the conversion was valid are represented in the return
>> type.
>>
>> Again, taking Rust just as an example, there is a standard way
>> to represent such conversions; the `TryFrom` trait (and it's
>> dual, `TryInto`). Consider this silly example problem: I have a
>> type representing colors; perhaps the only colors I care about
>> are Red, Green, and Blue. I can label these with integers, say
>> 1, 2 and 3, and I can represent this in Rust using an
>> enumeration.
>>
>> Now further suppose that I have a file of 8-bit bytes that
>> contain the (raw, integral) representation of these color
>> values; I'd like to convert these into proper objects of the
>> enumeration type, but of course, not all 8-bit byte values
>> represent valid colors, so the proper tool in this case is
>> `TryFrom`. Note, however, that converting back, from a color to
>> its 8-bit value, is _always_ valid, so I just use `From` in that
>> case (which also, conveniently, gives me `into`).
>
>> #[derive(Clone, Copy, Debug, Eq, PartialEq)]
>> enum Colors {
>> Red = 1,
>> Green = 2,
>> Blue = 3,
>> }
>>
>> impl TryFrom<u8> for Colors {
>> type Error = String;
>> fn try_from(raw: u8) -> Result<Self, Self::Error> {
>> match raw {
>> 1 => Ok(Self::Red),
>> 2 => Ok(Self::Green),
>> 3 => Ok(Self::Blue),
>> _ => Err(format!("unsupported value '{raw}'")),
>> }
>> }
>> }
>
>> Note the unit tests. Note also, that, as a result of the way
>> that the conversion is structured, as aided by the return type,
>> the conversion operation itself is safe.
>>
>> Of course, this example is trivial, but the same principle
>> applies for more comple conversions as well, including unsafe
>> conversions.
>>
>> Further, by localizing the unsafety inside of the conversion,
>> and using a return type that can represent failure, one can
>> construct a _safe_ interface to do _unsafe_ conversions.
>
>> In contrast, `Valid` is easy to misuse, primarily by not using
>> it at all, in which case you run the risk of raising a runtime
>> exception, or just having an incorrect program. With either
>> `Option` or `Result`, you are forced to contend with the error
>> case. The programmer can't forget to check.
>>
>> Finally, `Valid` is very limited in its applicability: it can
>> only be used with scalar types. At least in Rust, `Option` and
>> `Result` are generic over essentially arbitrary types.
>>
>> Put another way, if the language supports something like an
>> `Option` type, then there is no need for a special-case facility
>> like Ada's `Valid` attribute.
>
>All fine.
>
>But you can do the same in Ada.
Indeed, you can, but I never said you couldn't. My point was
that Ada's `Valid` attribute is overly specific, underpowered,
and ultimately unnecessary in a language that supports proper
sum types over generics. Ada's `Valid` attribute is neither as
general nor as robust as using an ADT like
Option/Result/Maybe/whatever it's called in any given langauge.
>Both doing similar to above and by using Unchecked_Conversion
>and Valid.
>
> [snip code segment for brevity]
>
>A bit verbose. But if one want short code, then
>Ada is not the right language choice.
Also not as general. Note that in the Rust example, `Option` is
generic over some type `T`: your example is concrete over the
color enum, and just colocates it with a flag and a convenience
method that returns null if the flag is false (but now all
accesses are via reference). As a simulacrum, it will serve,
but one could do that in any number of languages; even C with a
couple of accessor functions can do something similar.
But Ada supports generics (recall that Stepanov did the first
implementation of the STL in Ada). You could use that to build
an actual `Option` type that would closer to the Rust version.
It would probably not be as convenient to use because Ada lacks
Rust-style pattern matching and destructuring, but it would more
or less obviate the need for `Valid`.
>I am printing instead of asserting, because assertions was first
>to Ada 20 years ago and the VMS GNAT I have is over 25 years old.
Fortunately, Generics have been in the language since the 80s.
:-D
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2025-11-20 19:18 -0500 |
| Message-ID | <10fob5c$3aj3s$1@dont-email.me> |
| In reply to | #378198 |
On 11/20/2025 6:54 AM, Dan Cross wrote:
> In article <10flqou$2l1qc$1@dont-email.me>,
> Arne Vajhøj <arne@vajhoej.dk> wrote:
>> On 11/19/2025 11:02 AM, Dan Cross wrote:
>>> Further, by localizing the unsafety inside of the conversion,
>>> and using a return type that can represent failure, one can
>>> construct a _safe_ interface to do _unsafe_ conversions.
>>
>>> In contrast, `Valid` is easy to misuse, primarily by not using
>>> it at all, in which case you run the risk of raising a runtime
>>> exception, or just having an incorrect program. With either
>>> `Option` or `Result`, you are forced to contend with the error
>>> case. The programmer can't forget to check.
>>>
>>> Finally, `Valid` is very limited in its applicability: it can
>>> only be used with scalar types. At least in Rust, `Option` and
>>> `Result` are generic over essentially arbitrary types.
>>>
>>> Put another way, if the language supports something like an
>>> `Option` type, then there is no need for a special-case facility
>>> like Ada's `Valid` attribute.
>>
>> All fine.
>>
>> But you can do the same in Ada.
>
> Indeed, you can, but I never said you couldn't. My point was
> that Ada's `Valid` attribute is overly specific, underpowered,
> and ultimately unnecessary in a language that supports proper
> sum types over generics. Ada's `Valid` attribute is neither as
> general nor as robust as using an ADT like
> Option/Result/Maybe/whatever it's called in any given langauge.
Ada's valid does exactly what it is supposed to do: check if the
output from an Unchecked_Conversion meet the constraints of the
data type.
It is not a replacement for Option/Result.
It can be used to implement Option/Result for those
types that can be set with Unchecked_Conversion, but obviously
not for other data types.
A screwdriver is not good for hammering nails into wood,
but that does not mean that a screwdriver is a bad tool - it
is just not intended for that usage.
Regarding the risk of not being checked, then it is inherent
in the problem - no matter the mechanism used then the developer
can chose not to do it right, because "there will always be
a valid value here".
> Also not as general. Note that in the Rust example, `Option` is
> generic over some type `T`: your example is concrete over the
> color enum, and just colocates it with a flag and a convenience
> method that returns null if the flag is false (but now all
> accesses are via reference).
> But Ada supports generics (recall that Stepanov did the first
> implementation of the STL in Ada). You could use that to build
> an actual `Option` type that would closer to the Rust version.
Generics is one of those Ada features that I don't like to use.
But a generic version is attached below.
> It would probably not be as convenient to use because Ada lacks
> Rust-style pattern matching and destructuring, but it would more
> or less obviate the need for `Valid`.
Valid is still a way - probably the best way - to produce
the Option.
Arne
++++
$ type OptionPackage.ads
generic
type T is private;
package OptionPackage is
type Option(Valid : Boolean := False) is record
case Valid is
when False =>
null;
when True =>
Value : T;
end case;
end record;
function SomeValue(O : T) return Option;
function None return Option;
end OptionPackage;
$ type OptionPackage.adb
package body OptionPackage is
function SomeValue(O : T) return Option is
res : Option;
begin
res := (Valid => True, Value => o);
return res;
end SomeValue;
function None return Option is
res : Option;
begin
res := (Valid => False);
return res;
end None;
end OptionPackage;
$ type ColorFul3.adb
with Unchecked_Conversion;
with Ada.Text_IO, Ada.Integer_Text_IO;
with OptionPackage;
use Ada.Text_IO, Ada.Integer_Text_IO;
Procedure ColorFul3 is
type Color is (Red, Green, Blue);
for Color use (Red => 1, Green => 2, Blue => 3);
for Color'Size use Integer'Size;
procedure Put(col : Color) is
begin
case col is
when Red => Put("Red");
when Green => Put("Green");
when Blue => Put("Blue");
end case;
end Put;
package ColorOption is new OptionPackage(T => Color);
function Integer2ColorNice(I : Integer) return ColorOption.Option is
res : ColorOption.Option;
begin
case I is
when 1 => res := ColorOption.SomeValue(Red);
when 2 => res := ColorOption.SomeValue(Green);
when 3 => res := ColorOption.SomeValue(Blue);
when others => res := ColorOption.None;
end case;
return res;
end Integer2ColorNice;
function Integer2ColorTricky(I : Integer) return ColorOption.Option is
function BitI2C is new Unchecked_Conversion(Source => Integer, Target =>
Color);
temp : Color;
res : ColorOption.Option;
begin
temp := BitI2C(I);
if temp'Valid then
res := ColorOption.SomeValue(temp);
else
res := ColorOption.None;
end if;
return res;
end Integer2ColorTricky;
col : ColorOption.Option;
begin
for I in 0..4 loop
col := Integer2ColorNice(I);
Put(I, Width => 1);
Put(" is ");
if col.Valid then
Put(col.Value);
else
Put("not a valid color");
end if;
New_Line;
end loop;
for I in 0..4 loop
col := Integer2ColorTricky(I);
Put(I, Width => 1);
Put(" is ");
if col.Valid then
Put(col.Value);
else
Put("not a valid color");
end if;
New_Line;
end loop;
end ColorFul3;
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2025-11-21 03:03 +0000 |
| Message-ID | <10fokpt$f7e$1@reader2.panix.com> |
| In reply to | #378202 |
In article <10fob5c$3aj3s$1@dont-email.me>, Arne Vajhøj <arne@vajhoej.dk> wrote: >On 11/20/2025 6:54 AM, Dan Cross wrote: >> In article <10flqou$2l1qc$1@dont-email.me>, >> Arne Vajhøj <arne@vajhoej.dk> wrote: >>> On 11/19/2025 11:02 AM, Dan Cross wrote: >>>> Further, by localizing the unsafety inside of the conversion, >>>> and using a return type that can represent failure, one can >>>> construct a _safe_ interface to do _unsafe_ conversions. >>> >>>> In contrast, `Valid` is easy to misuse, primarily by not using >>>> it at all, in which case you run the risk of raising a runtime >>>> exception, or just having an incorrect program. With either >>>> `Option` or `Result`, you are forced to contend with the error >>>> case. The programmer can't forget to check. >>>> >>>> Finally, `Valid` is very limited in its applicability: it can >>>> only be used with scalar types. At least in Rust, `Option` and >>>> `Result` are generic over essentially arbitrary types. >>>> >>>> Put another way, if the language supports something like an >>>> `Option` type, then there is no need for a special-case facility >>>> like Ada's `Valid` attribute. >>> >>> All fine. >>> >>> But you can do the same in Ada. >> >> Indeed, you can, but I never said you couldn't. My point was >> that Ada's `Valid` attribute is overly specific, underpowered, >> and ultimately unnecessary in a language that supports proper >> sum types over generics. Ada's `Valid` attribute is neither as >> general nor as robust as using an ADT like >> Option/Result/Maybe/whatever it's called in any given langauge. > >Ada's valid does exactly what it is supposed to do: check if the >output from an Unchecked_Conversion meet the constraints of the >data type. Again. Ada's `Valid` attribute is overly specific (it cannot be repurposed for other things), underpowered (it only applies to scalars and, critically, can be ignored) and unnecessary if a language has an `Option` (`Maybe`) or `Result` (`Either`) type. >It is not a replacement for Option/Result. No, it is not. Indeed, it _cannot_ be since it is a strictly weaker construct in all respects. However, `Option` or `Result`, in conjunction with something like `TryFrom`, _can_ be a replacement for `Valid`, because things like `TryFrom` and `Option`/`Result` are more general and more powerful than `Valid`. >It can be used to implement Option/Result for those >types that can be set with Unchecked_Conversion, but obviously >not for other data types. It could be, but it doesn't _need_ to be. I can see how `Valid` might be _useful_. Unfortunately, the construct seems overly rooted in some fundamental assumptions that Ada made about the world back in the 70s and 80s. It's just been passed by by the state of the art since then, as has Ada more generally. That's a pity; Ada isn't a _bad_ language, but we have better alternatives now. >A screwdriver is not good for hammering nails into wood, >but that does not mean that a screwdriver is a bad tool - it >is just not intended for that usage. Non sequitur. You seem to be arguing something nobody was saying. What I am saying is that `Valid` isn't a great tool for its intended purpose. It's like trying to turn a phillips-head screw with a flat blade driver by sorta twisting it to the side.... >Regarding the risk of not being checked, then it is inherent >in the problem - no matter the mechanism used then the developer >can chose not to do it right, because "there will always be >a valid value here". Nope, this is wrong. The whole point of a Rust-style `Option` or `Result` is that you are no longer working in terms of the generic type T, but rather a wrapper around that type; if that wrapper has the value `None` then there is no T, so the statement, 'because "there will always be a valid value here"' is, by definition, incorrect. The programmer is forced to contend with this possibility because because the programmer is working in terms of the wrapper type (the `Option` itself, say) and not the underlying value type. That said, Cloudflare had a recent production outage because somebody called `unwrap` on a `Result` that was `Err`. Yeah, that was unwise. But note that this is qualitatively different: here, the programmer _chose_ to ignore the safety guidelines and unwrap something that wasn't known to be `Ok(...)`; this was an _active_ thing. That's different than omitting a check against the valid attribute, through carelessness or ignorance; that's a _passive_ thing.. >> Also not as general. Note that in the Rust example, `Option` is >> generic over some type `T`: your example is concrete over the >> color enum, and just colocates it with a flag and a convenience >> method that returns null if the flag is false (but now all >> accesses are via reference). > >> But Ada supports generics (recall that Stepanov did the first >> implementation of the STL in Ada). You could use that to build >> an actual `Option` type that would closer to the Rust version. > >Generics is one of those Ada features that I don't like to use. That's silly. It's a powerful construct that _should_ be used, though of course it has its costs (monomorphization on concrete types, primarily). >But a generic version is attached below. > >> It would probably not be as convenient to use because Ada lacks >> Rust-style pattern matching and destructuring, but it would more >> or less obviate the need for `Valid`. > >Valid is still a way - probably the best way - to produce >the Option. Well, perhaps, provided that the concrete type embedded in the `Option` will work with `Valid`; recall that `Valid` applies only to scalars. If the `Option` wraps a product type (records, etc) then `Valid` won't work, as it's not applicable in that context. But for scalars, whether it's the "best" way or not seems highly subjective. There are probably categories of scalar values that are difficult to represent using the language's type constraints and so for which `Valid` would not meanigfully apply, but something like, `TryFrom` might. For example, one might define a newtype over integers that represents primes; the invariant is that if an instance of that type exists at all, then it is guaranteed that the contained number must be prime. This is the sort of thing you _can_ check with an explicit conversion function, but _not_ with `Valid`. A nice property of using an `Valid` in your example `Option` type, however is that because the check for validity is encapsulated in the machinery built into the `Option` itself; the programmer cannot misuse it because its use is hidden from the programmer. >[snip] - Dan C.
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.os.vms
csiph-web