From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-3.3 required=3.0 tests=AWL,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.0 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id 60AFD1F42D for ; Wed, 23 May 2018 20:44:52 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id E9E311209A0; Thu, 24 May 2018 05:44:48 +0900 (JST) Received: from o1678948x4.outbound-mail.sendgrid.net (o1678948x4.outbound-mail.sendgrid.net [167.89.48.4]) by neon.ruby-lang.org (Postfix) with ESMTPS id D05BA12097F for ; Thu, 24 May 2018 05:44:46 +0900 (JST) Received: by filter0042p3las1.sendgrid.net with SMTP id filter0042p3las1-25777-5B05D2BC-2 2018-05-23 20:44:44.071290495 +0000 UTC Received: from herokuapp.com (ec2-54-224-21-149.compute-1.amazonaws.com [54.224.21.149]) by ismtpd0010p1iad1.sendgrid.net (SG) with ESMTP id aUhvi3jBTq-SB0jQb_A98g for ; Wed, 23 May 2018 20:44:43.967 +0000 (UTC) Date: Wed, 23 May 2018 20:44:44 +0000 (UTC) From: shevegen@gmail.com To: ruby-core@ruby-lang.org Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 62609 X-Redmine-Project: ruby-trunk X-Redmine-Issue-Id: 14784 X-Redmine-Issue-Author: zverok X-Redmine-Sender: shevegen X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: ync6xU2WACa70kv/Ymy4QrNMhiuLXJG8OTL2vJD1yS6Df7moE0zfVCsfw6yA6E92QWvBc2yMkxbLQ6 8XkQl50aXtFgB7sx9mvjngT06TwygtbzDBXtfVCgiKfmS9JbzWWDJMlAaNTO8ocaTO/AYg4xxAy2OG 1InsXxbJWwmVfcLnoc/FGAzwXJRMIjLp+na9rmV3LyC8XcTQKFGeAbKiMg== X-ML-Name: ruby-core X-Mail-Count: 87244 Subject: [ruby-core:87244] [Ruby trunk Feature#14784] One-sided Comparable#clamp X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #14784 has been updated by shevegen (Robert A. Heiler). Considering that Ranges allow a ruby hacker to omit the end value, for infinity/endless, I think your example makes sense in this regard, e. g. begin .. end being the same as: begin .. or begin.. Perhaps also the converse, but I have to admit that all these examples look very strange to my eyes. Like: clamp(..Date.today) I always look at it as if something is missing. Personally I prefer explicit "begin .. end". The: clamp(min: 0, max: 10) seems to be a nice API, in my opinion. At the least the names "min" and "max" appear explicit and make sense (to me). I agree, mostly for consistency, that if endless range has been accepted, being able to do so via #clamp may seem a logical continuation (to me). I am mostly neutral to the issue though, as I do not (yet) use clamp in my own ruby code. ---------------------------------------- Feature #14784: One-sided Comparable#clamp https://bugs.ruby-lang.org/issues/14784#change-72232 * Author: zverok (Victor Shepelev) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- **Proposal** Allow "one-sided" `clamp` to limit only upper bound (and, ideally, only lower too). Proposed implementation: allow `clamp(begin..end)` call sequence (without deprecating `clamp(begin, end)`), to take advantage from open-ended ranges with `clamp(begin..)`. **Reasoning about range** I looked through `#clamp` [discussion](https://bugs.ruby-lang.org/issues/10594), but couldn't find there why syntax `clamp(b, e)` was preferred to `clamp(b..e)`. The only one I could think of is possible confuse of how `clamp(b..e)` and `clamp(b...e)` behaviors should differ. The problem becomes more important with the introduction of [open-ended ranges](https://bugs.ruby-lang.org/issues/12912). I believe this is pretty natural: ```ruby some_calculation.clamp(0..) # now, I use clamp(0, Float::INFINITY) timestamp.clamp(Date.today..) # now, I typically use clamp(Date.today..INFINITE_FUTURE_DATE) with custom defined constant ``` Counter-arguments: 1. This is "one-sided", you can't do `clamp(..Date.today)`. To this I can answer than from my experience "clamping only minimum" is more frequent, and if you need to clamp only maximum, most of the time there is some "reasonable minumum". Another idea is that maybe this is a proof why "start-less" ranges are necessary, after all, [doubted here](https://bugs.ruby-lang.org/issues/12912#note-12) 2. Why not just leave current `clamp(b, e)` and allow `clamp(b)`? Answer: because when you see `clamp(10)`, is it `clamp(10, nil)`, or `clamp(nil, 10)` (yes, logically it is the first argument that is left, but from readability point of view it is not that obvious). Possible alternative: `clamp(min: 0, max: 10)`, where you can omit any of two. 3. Why do you need one-sided clamp at all? Because alternatives is much more wordy, making reader think: ```ruby # with clamp chain.of.calculations.clamp(0..) # without clamp v = chain.of.calculations v < 0 ? 0 : v # or, with yield_self (renamed to then) chain.of.calculations.then { |v| v < 0 ? 0 : v } ``` Both alternatives "without `#clamp`" shows intentions much less clear. -- https://bugs.ruby-lang.org/