एक प्रोग्रामिंग भाषा जो आपको सरल प्रकारों के लिए नई सीमाओं को परिभाषित करने की अनुमति देती है


19

कई भाषाओं को पसंद करते हैं C++, C#और Javaआपको उन वस्तुओं को बनाने की अनुमति देते हैं जो सरल प्रकारों का प्रतिनिधित्व करते हैं जैसे integerया float। एक वर्ग इंटरफ़ेस का उपयोग करके आप ऑपरेटरों को ओवरराइड कर सकते हैं और यदि कोई मान 100 के व्यापार नियम से अधिक है तो जाँच कर सकते हैं।

मुझे आश्चर्य हो रहा है कि क्या इन भाषाओं को किसी चर / संपत्ति के एनोटेशन या विशेषताओं के रूप में परिभाषित करना संभव है।

उदाहरण के लिए, C#आप लिख सकते हैं:

[Range(0,100)]
public int Price { get; set; }

या शायद C++तुम में लिख सकता है:

int(0,100) x = 0;

मैंने ऐसा कुछ भी कभी नहीं देखा है, लेकिन यह देखते हुए कि हम भंडारण से पहले डेटा सत्यापन पर निर्भर हो गए हैं। यह अजीब है कि इस सुविधा को भाषाओं में नहीं जोड़ा गया है।

क्या आप उन भाषाओं का उदाहरण दे सकते हैं जहाँ यह संभव है?


14
क्या एडा ऐसा कुछ नहीं है?
zxcdw

2
@zxcdw: हाँ, एडा पहली भाषा थी (जैसा कि मुझे पता है) जो इस तरह के "प्रकारों" के समर्थन में बनी है। नामित डेटा प्रकार।
m0nhawk

4
सभी निर्भर प्रकार की भाषाओं में यह क्षमता होगी। यह वास्तविक प्रकार से en.wikipedia.org/wiki/D dependent_type प्रकार की प्रणाली के लिए आंतरिक है, हालांकि आप किसी भी एमएल में इस प्रकार का एक कस्टम प्रकार बना सकते हैं, इन भाषाओं में एक प्रकार के रूप में परिभाषित किया गया है data Bool = True | Falseऔर आप जो कह सकते हैं data Cents = 0 | 1 | 2 | ...उसके लिए एक है "बीजीय डेटा प्रकार" को देखें (जिसे अधिक सटीक रूप से हिंद-मिलनर प्रकारों का नाम दिया जाना चाहिए, लेकिन लोग भ्रमित करते हैं कि प्रकार की असमानता के साथ) en.wikipedia.org/wiki/Algebraic_data_type
जिमी हॉफ

2
यह देखते हुए कि आप जिन भाषाओं को नामांकित करते हैं, वे पूर्णांक को कैसे कम करती हैं- और अंडरफ़्लो, इस तरह की सीमा का प्रतिबंध अपने आप में बहुत अधिक मूल्य का नहीं होगा यदि आप साइलेंट ओवर / अंडरफ़्लो रखते हैं।

9
@StevenBurnap: प्रकारों को OO की आवश्यकता नहीं होती है। typeपास्कल में एक कीवर्ड है। ऑब्जेक्ट ओरिएंटेशन प्रोग्रामिंग भाषाओं की "एटमार" संपत्ति की तुलना में एक डिजाइन पैटर्न का अधिक है।
सिरफिरे

जवाबों:


26

पास्कल के पास एक प्रकार की संख्या थी, यानी एक चर में फिट होने वाली संख्या की संख्या घटाना।

  TYPE name = val_min .. val_max;

Ada में भी श्रेणियों की एक धारणा है: http://en.wikibooks.org/wiki/Ada_Programming/Types/range

विकिपीडिया से…।

type Day_type   is range    1 ..   31;
type Month_type is range    1 ..   12;
type Year_type  is range 1800 .. 2100;
type Hours is mod 24;
type Weekday is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); 

भी कर सकते हैं

subtype Weekend is  Weekday (Saturday..Sunday);
subtype WorkDay is  Weekday (Monday..Friday);

और यहाँ है जहाँ यह शांत हो जाता है

year : Year_type := Year_type`First -- 1800 in this case...... 

C के पास एक सख्त सबरेंज प्रकार नहीं है, लेकिन बिट्स के उपयोग से बिट्स का उपयोग कम से कम करने के लिए एक (कम से कम सीमित) की नकल करने के तरीके हैं। struct {int a : 10;} my_subrange_var;}। यह चर सामग्री के लिए एक ऊपरी बाध्य के रूप में काम कर सकता है (सामान्य तौर पर मैं कहूंगा: इसके लिए बिटफ़िल्ड का उपयोग न करें , यह केवल एक बिंदु को प्रमाणित करने के लिए है)।

अन्य भाषाओं में मनमाने ढंग से लंबाई पूर्णांक प्रकारों के लिए बहुत सारे समाधान लाइब्रेरी-स्तर पर होते हैं, Ie C ++ टेम्पलेट आधारित समाधानों के लिए अनुमति देता है।

ऐसी भाषाएं हैं जो परिवर्तनशील राज्यों की निगरानी और इसके लिए अभिकथन को जोड़ने की अनुमति देती हैं। उदाहरण के लिए क्लोजरस्क्रिप्ट में

(defn mytest 
   [new-val] 
   (and (< new-val 10)
        (<= 0 new-val)))

(def A (atom 0 :validator mytest))

फ़ंक्शन mytestको कहा जाता है जब स्थिति aबदल जाती है ( reset!या के माध्यम से swap!) जाँच करता है कि क्या शर्तें पूरी हुई हैं। यह देर-बाइंडिंग भाषाओं में व्यवस्थित व्यवहार को लागू करने के लिए एक उदाहरण हो सकता है (देखें http://blog.fogus.me/2011/09/23/clojurescript-watchers-and-validators/ )।


2
यदि आप निर्भर प्रकारों के बारे में एक विवरण जोड़ेंगे, तो यह अच्छा होगा, यह समस्या संपूर्ण उद्देश्य और निर्भर टाइपिंग का कारण है, ऐसा लगता है कि इसे कम से कम उल्लेख किया जाना चाहिए (भले ही यह गूढ़ हो)
जिमी हॉफ

जबकि मुझे आश्रित प्रकार और आगमनात्मक तर्क / मिलिनर-प्रकार के अनुमान की कुछ समझ है। मेरे पास उन लोगों के साथ बहुत कम अभ्यास है। यदि आप मेरे उत्तर में जानकारी जोड़ना चाहते हैं तो इसे संपादित करने के लिए स्वतंत्र महसूस करें। मैं आगमनात्मक परिभाषा द्वारा गणित में Peano Axioms और संख्या प्रकारों के बारे में कुछ जोड़ने जा रहा था, लेकिन एक अच्छा एमएल डेटा उदाहरण शायद अधिक सार्थक हो सकता है।
सिरका

आप सी में एक प्रकार की सीमा का उपयोग कर सकते हैं enum का उपयोग कर
जॉन कार्टराईट

1
enum टाइप int या अहस्ताक्षरित int के afaik है (मुझे लगता है कि यह संकलक विशिष्ट है) और बाउंड-चेक नहीं किया गया है।
13'13

यह उससे अधिक ठंडा हो जाता है: रैंज प्रकारों को ऐरे घोषणाओं में इस्तेमाल किया जा सकता है और लूप for y in Year_Type loop ... ओवरफ्लो जैसी समस्याओं को खत्म करने के लिए ।
ब्रायन ड्रमंड

8

Ada भी एक ऐसी भाषा है जो सरल प्रकारों के लिए सीमा की अनुमति देती है, वास्तव में Ada में अच्छाई की गारंटी के लिए अपने कार्यक्रम के लिए अपने स्वयं के प्रकारों को परिभाषित करना अच्छा अभ्यास है ।

type MyType1   is range    1 .. 100;
type MyType2   is range    5 .. 15;

myVar1 : MyType1;

यह DoD द्वारा एक लंबे समय के लिए इस्तेमाल किया गया था, शायद अभी भी है, लेकिन मैंने इसका वर्तमान उपयोग खो दिया है।


2
Ada अभी भी सुरक्षा महत्वपूर्ण प्रणालियों में व्यापक रूप से उपयोग किया जाता है। विश्वसनीय और बनाए रखने योग्य सॉफ़्टवेयर लिखने के लिए भाषा को सबसे अच्छा उपलब्ध बनाने वाली भाषा के लिए हाल ही में एक अद्यतन है। दुर्भाग्य से उपकरण का समर्थन (संकलक, आईडीई परीक्षण ढांचे आदि) महंगा है और इसके साथ काम करने के लिए कठिन और अनुत्पादक बनाने में पिछड़ रहा है।
मटनज

शर्म आती है, मुझे पहली बार इसका उपयोग करना याद है और यह देखकर चकित था कि यह कोड कितना स्पष्ट और बग मुक्त है। यह सुनकर खुशी हुई कि यह अभी भी सक्रिय रूप से अपडेट है, फिर भी एक महान भाषा है।
लालचीबुद्ध

@ मट्टनज: जीएनएटी जीसीसी सुइट का हिस्सा है, और दोनों मुफ्त और भुगतान संस्करणों में मौजूद हैं।
कीथ थॉम्पसन

@keith: GNAT कंपाइलर मुफ्त है। आईडीई और रूपरेखा अभी भी महंगी हैं और कार्यक्षमता की कमी है।
मटनज

7

C ++ में श्रेणी-चेक किए गए मान प्रकार कैसे बनाएं के उदाहरणों के लिए C ++ में मूल्य प्रकारों की सीमा देखें ।

कार्यकारी सारांश: एक मूल्य प्रकार बनाने के लिए एक टेम्पलेट का उपयोग करें जिसमें बिल्ट-इन न्यूनतम और अधिकतम मान हैं, जिन्हें आप इस तरह उपयोग कर सकते हैं:

// create a float named 'percent' that's limited to the range 0..100
RangeCheckedValue<float, 0, 100> percent(50.0);

आपको वास्तव में यहां किसी टेम्पलेट की भी आवश्यकता नहीं है; आप इसी तरह के प्रभाव के लिए एक वर्ग का उपयोग कर सकते हैं। टेम्पलेट का उपयोग करने से आप अंतर्निहित प्रकार निर्दिष्ट कर सकते हैं। इसके अलावा, यह ध्यान रखना महत्वपूर्ण है कि percentऊपर का प्रकार एक नहीं होगा float, बल्कि टेम्पलेट का एक उदाहरण होगा। यह आपके प्रश्न के 'सरल प्रकार' पहलू को संतुष्ट नहीं कर सकता है।

यह अजीब है कि इस सुविधा को भाषाओं में नहीं जोड़ा गया है।

सरल प्रकार बस इतना ही है - सरल। वे अक्सर उपयोग किए जाने वाले उपकरणों को बनाने के लिए बिल्डिंग ब्लॉक के रूप में सबसे अच्छे रूप से उपयोग किए जाते हैं, बजाय सीधे उपयोग किए जाने के।


2
@JimmyHoffa जब मुझे लगता है कि कुछ मामले हैं जहां एक संकलक सीमा की स्थितियों का पता लगा सकता है, तो रेंज की जाँच ज्यादातर रन समय पर होने की आवश्यकता है। कंपाइलर संभवतः यह नहीं जान सकता है कि वेब सर्वर से जो मूल्य आप डाउनलोड करते हैं वह सीमा में होगा, या यदि उपयोगकर्ता एक सूची में कई रिकॉर्ड जोड़ देगा, या जो भी हो।
कालेब

7

आपके इरादे का कुछ प्रतिबंधित रूप मेरे ज्ञान जावा और सी # में एनोटेशन और डायनेमिक प्रॉक्सी पैटर्न के संयोजन के माध्यम से संभव है (जावा और सी # में डायनेमिक प्रॉक्सी के लिए अंतर्निहित कार्यान्वयन मौजूद है)।

जावा संस्करण

एनोटेशन:

@Target(ElementType.PARAMETER)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface IntRange {
     int min ();
     int max ();
}

प्रॉक्सी उदाहरण बनाने वाला रैपर वर्ग:

public class Wrapper {
    public static Object wrap(Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new MyInvocationHandler(obj));
    }
}

हर विधि कॉल पर बायपास के रूप में सेवारत InvocationHandler:

public class MyInvocationHandler implements InvocationHandler {
    private Object impl;

    public MyInvocationHandler(Object obj) {
        this.impl = obj;
    }

@Override
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    Annotation[][] parAnnotations = method.getParameterAnnotations();
    Annotation[] par = null;
    for (int i = 0; i<parAnnotations.length; i++) {
        par = parAnnotations[i];
        if (par.length > 0) {
            for (Annotation anno : par) {
                if (anno.annotationType() == IntRange.class) {
                    IntRange range = ((IntRange) anno);
                    if ((int)args[i] < range.min() || (int)args[i] > range.max()) {
                        throw new Throwable("int-Parameter "+(i+1)+" in method \""+method.getName()+"\" must be in Range ("+range.min()+","+range.max()+")"); 
                    }
                }
            }
        }
    }
    return method.invoke(impl, args);
}
}

उपयोग के लिए उदाहरण-इंटरफ़ेस:

public interface Example {
    public void print(@IntRange(min=0,max=100) int num);
}

मुख्य-विधि:

Example e = new Example() {
    @Override
    public void print(int num) {
        System.out.println(num);
    }
};
e = (Example)Wrapper.wrap(e);
e.print(-1);
e.print(10);

आउटपुट:

Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy0.print(Unknown Source)
at application.Main.main(Main.java:13)
Caused by: java.lang.Throwable: int-Parameter 1 in method "print" must be in Range (0,100)
at application.MyInvocationHandler.invoke(MyInvocationHandler.java:27)
... 2 more

सी # -संस्करण

एनोटेशन (C # नामक विशेषता में):

[AttributeUsage(AttributeTargets.Parameter)]
public class IntRange : Attribute
{
    public IntRange(int min, int max)
    {
        Min = min;
        Max = max;
    }

    public virtual int Min { get; private set; }

    public virtual int Max { get; private set; }
}

डायनामिकऑब्जेक्ट सब-क्लास:

public class DynamicProxy : DynamicObject
{
    readonly object _target;

    public DynamicProxy(object target)
    {
        _target = target;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        TypeInfo clazz = (TypeInfo) _target.GetType();
        MethodInfo method = clazz.GetDeclaredMethod(binder.Name);
        ParameterInfo[] paramInfo = method.GetParameters();
        for (int i = 0; i < paramInfo.Count(); i++)
        {
            IEnumerable<Attribute> attributes = paramInfo[i].GetCustomAttributes();
            foreach (Attribute attr in attributes)
            {
                if (attr is IntRange)
                {
                    IntRange range = attr as IntRange;
                    if ((int) args[i] < range.Min || (int) args[i] > range.Max)
                        throw new AccessViolationException("int-Parameter " + (i+1) + " in method \"" + method.Name + "\" must be in Range (" + range.Min + "," + range.Max + ")");
                }
            }
        }

        result = _target.GetType().InvokeMember(binder.Name, BindingFlags.InvokeMethod, null, _target, args);

        return true;
    }
}

उदाहरण:

public class ExampleClass
{
    public void PrintNum([IntRange(0,100)] int num)
    {
        Console.WriteLine(num.ToString());
    }
}

उपयोग:

    static void Main(string[] args)
    {
        dynamic myObj = new DynamicProxy(new ExampleClass());
        myObj.PrintNum(99);
        myObj.PrintNum(-5);
    }

अंत में, आप देखते हैं कि आप जावा में काम करने के लिए ऐसा कुछ प्राप्त कर सकते हैं , लेकिन यह पूरी तरह से सुविधाजनक नहीं है, क्योंकि

  • प्रॉक्सी क्लास केवल इंटरफेस के लिए तुरंत किया जा सकता है, यानी आपकी क्लास को एक इंटरफ़ेस लागू करना होगा
  • अनुमति सीमा केवल इंटरफ़ेस स्तर पर घोषित की जा सकती है
  • बाद में उपयोग केवल शुरुआत में अतिरिक्त प्रयास (MyInvocationHandler, हर तात्कालिकता पर रैपिंग) के साथ आता है, जो समझने की क्षमता को भी थोड़ा कम करता है

जैसा कि आप सी # कार्यान्वयन में देखते हैं, सी # में डायनामिकऑब्जेक्ट क्लास की क्षमताएं इंटरफ़ेस प्रतिबंध को हटा देती हैं। दुर्भाग्य से, यह गतिशील व्यवहार इस मामले में स्थिर प्रकार की सुरक्षा को हटा देता है, इसलिए यह निर्धारित करने के लिए रनटाइम जांच आवश्यक है कि क्या डायनेमिक प्रॉक्सी पर एक विधि कॉल की अनुमति है।

यदि वे प्रतिबंध आपके लिए स्वीकार्य हैं, तो यह आगे की खुदाई के लिए एक आधार के रूप में काम कर सकता है!


1
धन्यवाद, यह एक कमाल का जवाब है। क्या C # में ऐसा कुछ संभव है?
रिएक्टगुलर

1
बस एक नमूना जोड़ा # सी कार्यान्वयन!
मैकमैनस

बस FYI करें: public virtual int Min { get; private set; }एक अच्छी चाल है जो आपके कोड को काफी छोटा कर देगी
BlueRaja - Danny Pflughoeft

2
यह क्यू के बारे में पूरी तरह से अलग है, जो आप कर रहे हैं उसका कारण मूल रूप से गतिशीलता है; जो टाइपिंग का विरोधी है, जहां यह प्रश्न एक प्रकार के लिए पूछ रहा है, अंतर जब सीमा एक प्रकार पर होती है, तो इसे संकलित समय नहीं बल्कि समय पर लागू किया जाता है। किसी ने यह नहीं पूछा कि रन टाइम में पर्वतमाला को कैसे वैध किया जाए, वह चाहता था कि यह उस प्रकार की प्रणाली द्वारा मान्य हो जिसे संकलन समय पर जांचा जाता है।
जिमी होफा

1
@JimmyHoffa आह कि समझ में आता है। शुभ अंक :)
रिएक्टगुलर

2

रंग आक्रमणकारियों का एक विशेष मामला है। विकिपीडिया से:

एक आक्रमणकारी एक ऐसी स्थिति है जिसे किसी कार्यक्रम के निष्पादन के दौरान सच होने पर भरोसा किया जा सकता है।

एक श्रेणी [a, b]के रूप में एक चर घोषित किया जा सकता एक्स प्रकार के Integerअपरिवर्तनशीलताओं साथ एक्स> = एक और एक्स <= ख

इसलिए एडीए या पास्कल सब्रेंज प्रकार कड़े परिगलन नहीं हैं। उन्हें आक्रमणकारियों के साथ पूर्णांक प्रकार के साथ लागू किया जा सकता है।


0

यह अजीब है कि इस सुविधा को भाषाओं में नहीं जोड़ा गया है।

शक्तिशाली प्रकार के सिस्टम के साथ C ++ और अन्य भाषाओं में श्रेणी-सीमित प्रकारों के लिए विशेष सुविधाओं की आवश्यकता नहीं है।

C ++ में, आपके लक्ष्य को उपयोगकर्ता-परिभाषित प्रकारों के साथ अपेक्षाकृत सरल रूप से पूरा किया जा सकता है । और ऐसे अनुप्रयोगों में जहां रेंज-सीमित प्रकार वांछनीय हैं, वे शायद ही पर्याप्त हैं । उदाहरण के लिए, कोई यह भी संकलक को सत्यापित करना चाहेगा कि भौतिक इकाई संगणनाएँ सही लिखी गई थीं, ताकि वेग / समय एक त्वरण पैदा करता है, और त्वरण / समय का वर्गमूल लेने से वेग उत्पन्न होता है। ऐसा करने में आसानी से हर प्रकार के नामकरण के बिना किसी प्रकार की प्रणाली को परिभाषित करने की क्षमता की आवश्यकता होती है, जो कभी भी एक सूत्र में प्रकट हो सकती है। यह C ++ में किया जा सकता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.