Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125054 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 4C8D11A00BD for ; Mon, 19 Aug 2024 22:17:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1724105954; bh=fJbSFfKagMZ6taPlrLLVrk7oFplOydTxbNTo6GFkhXs=; h=Date:Subject:To:References:From:In-Reply-To:From; b=UqzoACmHghFBHxDNHHgPRz4LDi+KwVa0Mi6GRA/Q2syyUYWEpAKX9v7B54Oe3mP9j iu18/L1oqd+DT++AaChq610ejeYi2iICurLow+gKVolSzVbrYbF/hJcPFRhFZCyyuQ riGkgHrGjtsaTYosJkZO9mVY/t+aAkTtqsorj8Y8vOLXzW+1wliFDxMbKoVQKE25fQ nwcKBklU223M5c9/xhrQPNYRqFq/qNkCTG1ydon89NulVWWOHDuV/CNi2zBcUR9Rji 3J2YjQ0iaSMvK6pHQZqcbaZofsT6tEtUJR3bNdmAdnmMhLEA/mKOTFnE2RlRKREJ+Z oqFq/+FKIEKOg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 1211F180034 for ; Mon, 19 Aug 2024 22:19:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_50, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS, FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05olkn2085.outbound.protection.outlook.com [40.92.91.85]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 19 Aug 2024 22:19:09 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=iqX3zBDQxqVetqF0kSMV4y+0xsHu9du3eyEt/Q5ZGIXunVzM9O5X5yvgjjqmtQ2jnceMhn91zcLgq6F9ks228CpeWTxG7tKWb2OX5yLrIhxuogHCGFk7lODWwq/OZq/g1dWPSBdzfGqIEZoVacBn3VDVi5QnsUJ86R26P3RnNEh/Wt6gHIF2DgvUAbby304ElXGQ/img7Mc1E+wAB9Yodrux1jc+ar3q/3c8XNVk9gXsh6apdzqTdJmCJ986C3jkg9JhSqnCx4jpIacC5bbsjm6rbdI2a9/7GkfMjwYJXXz+m1u+rw3g37c1BeLks0LGkVJU8wUOkjKGzd22nYYHGQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=OnUt2gqWXnYPLm7Xku8cU11NVAfjOjpElWK/YBXoCpY=; b=cRQ+fea5gON2lJRPcmRZyUR3AgvilXZlx8h1D1bnqFW7DXFVUl7UkuI0QMwBsnPh4AdOJ4G0L+eij4J4WzE86rx+i5Sys3EUNStd1KuPd4PgbKZS/PlFQWrdJifJQ2g2fO73nDtkIPo8uCzYAf/bmiUEanIUfB3UhNibX74vGPdcSo/EChbK8zW0ZCGBGEmHOYLMzxwNs6URpjWoBFdipQESVxwa3RxD0ZawiSO3qoIv9PV+MQId8hyxHKEa6Ucj3FbfSm8egaQLdyGhjnApi/QVdBduK0z8eB9P3hf/3fqKPfyJTN4fsC5SX9zEapzzHHgi/aEoqEtQFkjiC5iXTQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hotmail.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=OnUt2gqWXnYPLm7Xku8cU11NVAfjOjpElWK/YBXoCpY=; b=Cqn9parzmyzC32cqQ/6EYmvDTIQns8xMZg14qpyGSgopSqOyPo7tzzPrJBisfqXmf1ADr/brTlVJI+rGAZ4V5cSFmTfPHinId08uZjUi9dAVoF8+Z3xmMjAE3AzG/fqvaAu5cMxCoid/Les8V1m8rTPmlqYrywtKOwOnEpv3+jVOqfg9/2MK/XM3n4bFjIk/ltygH/Px2K3ogO8ymiO0C869RXXA6q5mMx4cvn7GOLC6Sv3bxL99d9bLAQaOrSuoWGofGXoa81FDCgUajXrBgbfaGuxTFKInn/iciOj28zCzwU6ytvgJtLr26fPQeGhG9SzGp9F0k3fHDUwcgrwjvg== Received: from AM8P250MB0170.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:321::21) by AM8P250MB0294.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:329::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7875.25; Mon, 19 Aug 2024 22:16:54 +0000 Received: from AM8P250MB0170.EURP250.PROD.OUTLOOK.COM ([fe80::651e:bbd2:b18a:80ff]) by AM8P250MB0170.EURP250.PROD.OUTLOOK.COM ([fe80::651e:bbd2:b18a:80ff%6]) with mapi id 15.20.7875.019; Mon, 19 Aug 2024 22:16:54 +0000 Content-Type: multipart/alternative; boundary="------------jVUgXU605CuqUyvpTC3lr832" Message-ID: Date: Tue, 20 Aug 2024 00:16:53 +0200 User-Agent: Mozilla Thunderbird Subject: Re: [PHP-DEV] State of Generics and Collections To: Derick Rethans , PHP Developers Mailing List References: <1b59392a-68cb-36eb-0fef-977ac7113520@php.net> Content-Language: en-US In-Reply-To: <1b59392a-68cb-36eb-0fef-977ac7113520@php.net> X-TMN: [2bDqysAaNG8O3NUvRhRPUKRykNHaZZHDuwTdrEZ9XMvzEc7m+c7oAEYC7y5LbwBc] X-ClientProxiedBy: PA7P264CA0395.FRAP264.PROD.OUTLOOK.COM (2603:10a6:102:399::26) To AM8P250MB0170.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:321::21) X-Microsoft-Original-Message-ID: Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM8P250MB0170:EE_|AM8P250MB0294:EE_ X-MS-Office365-Filtering-Correlation-Id: ba49ce70-766f-435c-f6b9-08dcc09ca1b0 X-Microsoft-Antispam: BCL:0;ARA:14566002|8060799006|461199028|12050799009|15080799003|19110799003|9400799024|5072599009|440099028|4302099013|3412199025|1602099012; X-Microsoft-Antispam-Message-Info: swS2tNUZ7Vx2Wrb4HryqTMxUqDhKA6o5K/GYM67Zkbuu249YgYYQFMVZKdTqoTTjtM9EJGA3MBni77RFpwKNLtzCfO1Qk2Yvtt/NM2MVz2OmAkOxYDEpp4rs43t4fx5MhjE3TgEnVEz3NL0JZQvwoQmVqyiFHJLrSx8AAUH2moRMuODBk9N97sU4MFsf1uHOY1NM9D2dbqvd0e8Tl0yxGCDAIQcnWyhupdiP6rqSc/3SRxN7U75Qi9VIKBGxtDdwFXcAlwTzONlOJM4BL5XLE1s/7npY/KwhwDsMDbX83+CMARKz1ZhUTulkDC0EKSh0Wm3nDk+TDgaBOS+aTBJivyI6YrjEMr33WSAnt/zSGb/xmo3ekmUw1AHqodjSp13Zqn4kKxCOinc+/VYGJHcZMi2FdlZsXn0Vnt0bAnmnH90WeaCVYWmm+vHUQlzbhQLXivRn/uzg2Dd/dtQU+pRkv+tFui+AR7CgHstCrEiywNTvCj+9QhdGITDnYtkSufv9QXlX2VWR9UgC0eoJUs40+Vh8KIUg7QMPetqKBh60Dx/Hqf7Ver+qxYKQUGkIOAzOp12KvVNPyHgDqAFXtbs8ZHuJGnkH+jeKig9jjS1WCR27rGCZXc9XNvgOyhzsKFf5WEKExcg7+O2lmLS8taJJoBaRZcp18JYdq18yUOPwkeg0XyjM8DLkmZXVOC1m8aHPlLSMIKLpjkR4Ndh6DY3QumrRVdESrv4HZc9T86heMTKXP/JqCkQs4vGWxw7qeCJiTLXpElNVfk0SvzCH2K3p4jGW/azvXy8sBcBqd1ZH7Tpk/DcQjojNZtcxxeVcR2yQgdWHiO2pl5da55vBkGcIrtI+jX2z6rm+4e4fjs89JTZLz9+w5ksSXoaKIVEvb9bF X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZnZaaTRNUTdNbUxZQmlZb1JWcitDdktDNDBOQlFZTCs2dFJUWmxxbCtWSHpH?= =?utf-8?B?SVFqMWtnempoV2RsSkZ6TnZaemFoZ2hrQnYwQzFEYlJrYVYyZkQycmdNU2tJ?= =?utf-8?B?dWhqbG5HNWxyMmdCTDd2S3pLdEo0SHN3WHhNZ0gxTGlzck15WTV0bmY0c3BY?= =?utf-8?B?LzhzOGV6N2p4bkxWeEpVSmxNZzMvRXNTbXNKblQrUm51VFBEdnFzdmM3NDFF?= =?utf-8?B?enVVTzhaaEJFd0NJUnFKT05oam9JTHBaM1UyMmFMMS9LTDhZOUZwNjBoMEw0?= =?utf-8?B?Nk5rY0NLVFZDU015emJQdTZvYUcra01IRUNUaFdlY2w4cWtFTG5xdkFpU1B4?= =?utf-8?B?THVLNk0xSWExMlgxRE5yQXJYd1FXZEN2Ty9SbEJiaFJoKy9JV24vY2FuaS9Z?= =?utf-8?B?SFR2M0cvbW9SaTVjRmNJWEVBVkRBTm5pTFFXUVNsNy9QQ3V0VjJHZ2xnWXJT?= =?utf-8?B?Ky9xRVYrVkU4V1Foc1VkRHV0M2NkaTY5c3pDRzV5YjFxU1VoTzZ5THJyZkhj?= =?utf-8?B?dlJURDJoOXdmbkdrZ0pad3U2emMzSmt5QmxkRUVheWJNQ2luM01NbXEvb2hB?= =?utf-8?B?Um9OVnd3UTZHUkE4TXI3YWZDV3FRUDBGVjd4bTF4NVVOd0hEaDNySkZxQStX?= =?utf-8?B?NENFdHRMczdwZEhNdVd5SU1Id1YzSXVRUHp6UnhCT0dZLzBSc0JNNUtPL3lv?= =?utf-8?B?alBwWUk2c0o3VXY1Rms0cFQvUWNWb0JreS9Uc0lZeTdydS9OM0N6UDJYVmI5?= =?utf-8?B?WU5LU3BpbVg4NHFoeHJhUnBjT29ESHhyZURTWEQ3dU82OTVBYkhCRXRvMEhX?= =?utf-8?B?azZpZnFIcmxZazljaSszaWNyWFE3aDhJR04xSFBQSXNTM0ZhMGNXKytFMUIw?= =?utf-8?B?aUwwVnV1eTRmcXNKOUpxdW44VXU1OE8rL2RpMWtVVnEvcUY1TEMrNjZDdEdy?= =?utf-8?B?OWxKTXBhQVhrR2N6Qm1JdjlUNWtDSXh3VzgyMUFmeWR2VmZlcGl1Znhsd1Ny?= =?utf-8?B?MHRPQXhJdzAvWmk2WUFWblVsaHdOSjhkaGdGQ2ZoVDF2bmpBblo5MmdMQURl?= =?utf-8?B?bCsySHVnNGRuNjFqN2hCc1dMaDZ3UVBBa3Z1d2JjSU1qalhFNDhJbEUvRVNK?= =?utf-8?B?ZjFNSHpFWmJ4WVo1NXlPRkJlaWZhdnJtb1dPNXN1L1dManlGNlU4N0J4YTR2?= =?utf-8?B?bWh1Z20zRWQxa1BoRUt2TWcvQVMzRFFDQ1lDTTQ2amV2aXEwV3gxMTRSY3Nl?= =?utf-8?B?OFdEMTl2SjlPRFNUQ056TDJqSC9iT05CdEU5MGhrUXJ4MldQcnBrSUJrRFo0?= =?utf-8?B?R3ZRU2JPQkp1NWJsYzNueURYRjFLU2d5b2U1K2NRWDVPM1Q0WUR4MWpBdXQy?= =?utf-8?B?dVEzZFkxNHo0cGFob3gxM1RJRTNWVDhyQzlEV3ErU2s3Um83ZFlZNkdGV3VG?= =?utf-8?B?Rm5IaDhsVjVMc00rS0VJa3h6TWhVR1lSWVdJdytteG9YVm5rc25zRU5QeEZm?= =?utf-8?B?Qm9WbVNGOXNPWGZwdS9EeEZ5dXdCb3NDV2tpTjhhbDZ6NklQdHAwaUN2Q1dO?= =?utf-8?B?bWMrL1BNN1ptaXUrYkNOTVFKemh4aURhb1RQV0VLdEMxRGVNYjdwMHB0bTEv?= =?utf-8?B?elZaWS9QbnBtSEJtU0hseHdhTFlEbUZVVlJhaEM2TWljZTc5cXpXaUNvR2NF?= =?utf-8?B?UHVITi9jSEkxanQ3ZStOVzZGZ0R1OCtFWUpQbFYrTExMbHd6UXlHNmZod3Y1?= =?utf-8?Q?HT57IvQW3N3nyClRdk=3D?= X-OriginatorOrg: sct-15-20-7784-11-msonline-outlook-95b76.templateTenant X-MS-Exchange-CrossTenant-Network-Message-Id: ba49ce70-766f-435c-f6b9-08dcc09ca1b0 X-MS-Exchange-CrossTenant-AuthSource: AM8P250MB0170.EURP250.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Aug 2024 22:16:54.3687 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM8P250MB0294 From: bobwei9@hotmail.com (Bob Weinand) --------------jVUgXU605CuqUyvpTC3lr832 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 19.8.2024 19:08:32, Derick Rethans wrote: > Hi! > > Arnaud, Larry, and I have been working on an article describing the > state of generics and collections, and related "experiments". > > You can find this article on the PHP Foundation's Blog: > https://thephp.foundation/blog/2024/08/19/state-of-generics-and-collections/ > > cheers, > Derick Hey Derick, The fluid Arrays section says "A PoC has been implemented, but the performance impact is still uncertain". Where may I find that PoC for my curiosity? I'm imagining the implementation of the array types as a counted collection of types of the entries. But without the PoC I may only guess. It also says "Another issue is that [...] typed properties may not be possible.". Why would that be the case? Essentially a typed property would just be a static array, which you describe in the section right below. Also you are mentioning references. References to static arrays (typed property case) are trivial. References to fluid arrays would probably require runtime lookup of the contained references to determine the actual full type. Which may be a valid tradeoff, given that the very most arrays don't contain any or many references. ("Either you don't use references or you pay an O(contained references) overhead when passing around.") So, reading the conclusion, I'm a bit taken disappointed by: > * Halt efforts on typed arrays, as our current thoughts are that it > is probably not worth doing, due to the complexities of how arrays > work, and the minimal functionality that it would bring. > I'd truly appreciate more investigation into the topic, as I feel the functionality would definitely not be minor to PHP users. Regarding the Collections PR, I personally really don't like it: * It implements something which would be trivial if we had reified generics. If this ever gets merged, and generics happen later, it would be probably outdated and quirkiness the language has to carry around. * It's not powerful. But rather a quite limited implementation. No overrides of the built-in methods possible. No custom operations ("I want a dict where a specific property on the key is the actual unique key", "I want a custom callback be executed for each modification"). It's okay as a PoC, but far from a complete enough implementation. * It's a very specialized structure/syntax, not extensible for userland at all. Some functionality like generic traits, where you'd actually monomorphize the contained methods would be much more flexible. E.g. class Articles { use Sequence
; }. Much less specialized syntax, much more extensible. And generic traits would be doable, regardless of the rest of the generics investigation. In fact, generic traits (essentially statically replacing the generic arguments at link-time) would be an useful feature which would remain useful even if we had fully reified generics. I recognize that some functionality will need support of internal zend_object_handlers. But that's not a blocker, we might provide some default internal traits with PHP, enabling the internal class handlers. So to summarize, I would not continue on that path, but really invest into monomorphizable generic traits instead. Remains the last point about erased generics being acceptable: * If we ever end up adding actual reified generics (maybe due to a renewed investigation in 5 years), we'll most likely want to retain the syntax. There may be some syntax which cannot be supported though, or semantics which would have to break existing code. * Docblocks sort of an extensible and modifiable standard. Some type checkers allow e.g. List. But PHP certainly won't support it. So you will end up in a hybrid state where some functions use generics and some use only docblocks, because they're not powerful enough. Further, if you use both (e.g. List in definition, List in docblock), you also have to make sure to keep them in sync, because the generic type doesn't get verfied through execution. * We're used to "all types specified are checked". And that's a good thing. It sets expectations. Now imagine we're introducing type aliases. "type IntList = List;". Function signature "function processIntegers(IntList $list)". This looks like I could expect something actually being an IntList. There's no generic immediately in sight telling me that this is only going to provide me a List of arbitrary values. I will expect an IntList. Just like I will expect any bare "int" type to also give me an integer. So, overall, I think erased generics set the wrong expectations and have quite a risk to be a bad decision in light of possible future improvements. I'd also like to leave a small side note on this question: > What generic features are acceptable to leave out to make the > implementation more feasible? I think this asks the wrong question. First, figure out, what generic features really cannot make it, then figure out whether omitting these features is acceptable. Thanks all for investing time into this topic, I'm sure it will bring the language forward! Bob --------------jVUgXU605CuqUyvpTC3lr832 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit
On 19.8.2024 19:08:32, Derick Rethans wrote:
Hi!

Arnaud, Larry, and I have been working on an article describing the 
state of generics and collections, and related "experiments".

You can find this article on the PHP Foundation's Blog:
https://thephp.foundation/blog/2024/08/19/state-of-generics-and-collections/

cheers,
Derick

Hey Derick,

The fluid Arrays section says "A PoC has been implemented, but the performance impact is still uncertain". Where may I find that PoC for my curiosity? I'm imagining the implementation of the array types as a counted collection of types of the entries. But without the PoC I may only guess.

It also says "Another issue is that [...] typed properties may not be possible.". Why would that be the case? Essentially a typed property would just be a static array, which you describe in the section right below.

Also you are mentioning references. References to static arrays (typed property case) are trivial. References to fluid arrays would probably require runtime lookup of the contained references to determine the actual full type. Which may be a valid tradeoff, given that the very most arrays don't contain any or many references. ("Either you don't use references or you pay an O(contained references) overhead when passing around.")


So, reading the conclusion, I'm a bit taken disappointed by:

  • Halt efforts on typed arrays, as our current thoughts are that it is probably not worth doing, due to the complexities of how arrays work, and the minimal functionality that it would bring.
I'd truly appreciate more investigation into the topic, as I feel the functionality would definitely not be minor to PHP users.


Regarding the Collections PR, I personally really don't like it:

  • It implements something which would be trivial if we had reified generics. If this ever gets merged, and generics happen later, it would be probably outdated and quirkiness the language has to carry around.
  • It's not powerful. But rather a quite limited implementation. No overrides of the built-in methods possible. No custom operations ("I want a dict where a specific property on the key is the actual unique key", "I want a custom callback be executed for each modification"). It's okay as a PoC, but far from a complete enough implementation.
  • It's a very specialized structure/syntax, not extensible for userland at all. Some functionality like generic traits, where you'd actually monomorphize the contained methods would be much more flexible. E.g. class Articles { use Sequence<Article>; }. Much less specialized syntax, much more extensible. And generic traits would be doable, regardless of the rest of the generics investigation.
    In fact, generic traits (essentially statically replacing the generic arguments at link-time) would be an useful feature which would remain useful even if we had fully reified generics.
    I recognize that some functionality will need support of internal zend_object_handlers. But that's not a blocker, we might provide some default internal traits with PHP, enabling the internal class handlers.

So to summarize, I would not continue on that path, but really invest into monomorphizable generic traits instead.


Remains the last point about erased generics being acceptable:

  • If we ever end up adding actual reified generics (maybe due to a renewed investigation in 5 years), we'll most likely want to retain the syntax. There may be some syntax which cannot be supported though, or semantics which would have to break existing code.
  • Docblocks sort of an extensible and modifiable standard. Some type checkers allow e.g. List<positive-int>. But PHP certainly won't support it. So you will end up in a hybrid state where some functions use generics and some use only docblocks, because they're not powerful enough. Further, if you use both (e.g. List<int> in definition, List<positive-int> in docblock), you also have to make sure to keep them in sync, because the generic type doesn't get verfied through execution.
  • We're used to "all types specified are checked". And that's a good thing. It sets expectations.
    Now imagine we're introducing type aliases. "type IntList = List<int>;". Function signature "function processIntegers(IntList $list)". This looks like I could expect something actually being an IntList. There's no generic immediately in sight telling me that this is only going to provide me a List of arbitrary values. I will expect an IntList. Just like I will expect any bare "int" type to also give me an integer.

So, overall, I think erased generics set the wrong expectations and have quite a risk to be a bad decision in light of possible future improvements.


I'd also like to leave a small side note on this question:

What generic features are acceptable to leave out to make the implementation more feasible?
I think this asks the wrong question. First, figure out, what generic features really cannot make it, then figure out whether omitting these features is acceptable.


Thanks all for investing time into this topic, I'm sure it will bring the language forward!

Bob

--------------jVUgXU605CuqUyvpTC3lr832--