कोडिंग शैली का मुद्दा: क्या हमारे पास ऐसे कार्य होने चाहिए जो एक पैरामीटर लेते हैं, इसे संशोधित करते हैं, और फिर उस पैरामीटर को फिर से बनाते हैं?


19

मैं अपने दोस्त के साथ इस बात पर थोड़ी बहस कर रहा हूं कि क्या ये दोनों प्रथाएं एक ही सिक्के के दो पहलू हैं, या क्या वास्तव में बेहतर है।

हमारे पास एक फ़ंक्शन है जो एक पैरामीटर लेता है, इसका एक सदस्य भरता है, और फिर इसे वापस करता है:

Item predictPrice(Item item)

मेरा मानना ​​है कि जैसा कि यह उसी वस्तु पर काम करता है जिसे पारित किया जाता है, आइटम को वापस करने के लिए कोई बिंदु नहीं है। वास्तव में, अगर कुछ भी, फोन करने वाले के दृष्टिकोण से, यह मायने रखता है क्योंकि आप उम्मीद कर सकते हैं कि यह एक नया आइटम वापस कर देगा जो यह नहीं करता है।

वह दावा करता है कि इससे कोई फर्क नहीं पड़ता है, और इससे कोई फर्क नहीं पड़ता कि क्या उसने एक नया आइटम बनाया और वापस लौटा। मैं निम्नलिखित कारणों से बहुत असहमत हूं:

  • यदि आपके पास (या पॉइंटर्स या जो भी) आइटम पास के कई संदर्भ हैं, तो यह एक नई वस्तु आवंटित करता है और इसे वापस करना भौतिक महत्व का है क्योंकि ये संदर्भ गलत होंगे।

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

  • ढेर पर आवंटन संभावित रूप से महंगा है, और इसलिए यह महत्वपूर्ण है कि क्या यह कहा जाता है।

इसलिए, मेरा मानना ​​है कि यह एक विधि हस्ताक्षर के माध्यम से देखने में सक्षम होना बहुत महत्वपूर्ण है कि क्या यह एक वस्तु को संशोधित करता है, या एक नया आवंटित करता है। परिणामस्वरूप, मेरा मानना ​​है कि चूंकि फ़ंक्शन केवल पास की गई वस्तु को संशोधित करता है, हस्ताक्षर होना चाहिए:

void predictPrice(Item item)

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

तो, कोई विचार?


strcat जगह में एक पैरामीटर को संशोधित करता है और फिर भी इसे लौटाता है। क्या स्ट्रैट को शून्य होना चाहिए?
जेरी यिर्मयाह

जावा और सी ++ में पासिंग पैरामीटर के संबंध में बहुत अलग व्यवहार है। यदि Itemहै class Item ...और नहीं typedef ...& Item, तो स्थानीय itemपहले से ही एक कॉपी है
Caleth

google.github.io/styleguide/cppguide.html#Output_Parameters Google आउटपुट के लिए RETURN मान का उपयोग करता है
Firegun

जवाबों:


26

यह वास्तव में एक राय का विषय है, लेकिन इसकी कीमत क्या है, इसके लिए मुझे संशोधित वस्तु को वापस करना भ्रामक लगता है यदि आइटम को संशोधित किया जाता है। अलग-अलग, यदि predictPriceआइटम को संशोधित करने जा रहा है , तो इसका एक नाम होना चाहिए जो इंगित करता है कि यह ऐसा करने जा रहा है (जैसे setPredictPriceया कुछ ऐसा)।

मैं पसंद करूंगा (क्रम में)

  1. यह predictPriceएक तरीका थाItem (इसके न होने का एक अच्छा कारण है, जो आपके समग्र डिजाइन में अच्छा हो सकता है) - या तो

    • अनुमानित कीमत लौटा दी, या

    • की setPredictedPriceजगह नाम था

  2. यह संशोधित predictPrice नहीं हुआItem , लेकिन अनुमानित मूल्य वापस आ गया

  3. वह predictPriceएक voidविधि कहलाती थीsetPredictedPrice

  4. वह predictPriceलौट आया this(जो भी इसका एक हिस्सा है, उस पर अन्य तरीकों के लिए विधि के लिए) (और कहा जाता था setPredictedPrice)


1
उत्तर के लिए धन्यवाद। 1 के संबंध में, हम आइटम के अंदर भविष्यवाणियां करने में असमर्थ हैं। 2 एक अच्छा सुझाव है - मुझे लगता है कि शायद यहाँ सही समाधान है।
स्क्वीमी

2
@Squimmy: और यकीन है कि पर्याप्त है, मैं सिर्फ 15 मिनट किसी का उपयोग कर की वजह से एक बग के साथ काम कर खर्च वास्तव में : पैटर्न है कि आप के खिलाफ बहस कर रहे थे a = doSomethingWith(b) संशोधित b और संशोधन, जो बाद में मेरी कोड को विस्फोट से उड़ा दिया सोचा पर है कि यह पता था कि क्या के साथ वापस आ bपड़ा इस में। :-)
टीजे क्राउडर

11

ऑब्जेक्ट ओरिएंटेड डिज़ाइन प्रतिमान के भीतर, वस्तुओं को ऑब्जेक्ट के बाहर ही संशोधित नहीं किया जाना चाहिए। किसी वस्तु की स्थिति में कोई भी परिवर्तन वस्तु पर विधियों के माध्यम से किया जाना चाहिए।

इस प्रकार, void predictPrice(Item item)कुछ अन्य वर्ग के सदस्य कार्य के रूप में गलत है । सी के दिनों में स्वीकार्य हो सकता था, लेकिन जावा और सी ++ के लिए, किसी वस्तु के संशोधनों से उस वस्तु के लिए एक गहरी युग्मन होता है जो संभवतः सड़क के नीचे अन्य डिजाइन मुद्दों को जन्म देगा (जब आप कक्षा को रिफैक्ट करते हैं और अपने खेतों को बदलते हैं, अब उस 'प्रेडिक्टप्राइस' को किसी दूसरी फाइल में बदलने की जरूरत है।

किसी नई वस्तु को वापस करने से संबंधित दुष्प्रभाव नहीं होते हैं, जो पैरामीटर पास किया गया है, उसे बदला नहीं गया है। आप (predictPrice विधि) यह नहीं जानते कि उस पैरामीटर का उपयोग कहां और कैसे किया जाता है। है Itemएक हैश कहीं के लिए एक महत्वपूर्ण? क्या आपने ऐसा करने में इसका हैश कोड बदल दिया? क्या कोई दूसरा व्यक्ति इस पर पकड़ बना रहा है और यह उम्मीद कर रहा है कि यह नहीं बदलेगा?

ये डिज़ाइन मुद्दे ऐसे हैं जो दृढ़ता से सुझाव देते हैं कि आपको वस्तुओं को संशोधित नहीं करना चाहिए (मैं कई मामलों में अपरिवर्तनीयता के लिए तर्क दूंगा), और यदि आप करते हैं, तो राज्य के परिवर्तनों को किसी चीज़ के बजाय ऑब्जेक्ट द्वारा ही समाहित और नियंत्रित किया जाना चाहिए। क्लास के बाहर।


यदि कोई हैश में किसी चीज़ के खेतों से टकराता है तो क्या होता है, इसे देखें। कुछ कोड लेते हैं:

import java.util.*;

public class Main {
    public static void main (String[] args) {
        Set set = new HashSet();
        Data d = new Data(1,"foo");
        set.add(d);
        set.add(new Data(2,"bar"));
        System.out.println(set.contains(d));
        d.field1 = 2;
        System.out.println(set.contains(d));
    }

    public static class Data {
        int field1;
        String field2;

        Data(int f1, String f2) {
            field1 = f1;
            field2 = f2;
        }

        public int hashCode() {
            return field2.hashCode() + field1;
        }

        public boolean equals(Object o) {
            if(!(o instanceof Data)) return false;
            Data od = (Data)o;
            return od.field1 == this.field1 && od.field2.equals(this.field2);

        }
    }
}

ideone

और मैं मानता हूं कि यह सबसे बड़ा कोड नहीं है (सीधे खेतों तक पहुंच), लेकिन यह एक म्यूटेबल डेटा के साथ एक मुद्दे को प्रदर्शित करने के अपने उद्देश्य को पूरा करता है, जिसका उपयोग हाशप की कुंजी के रूप में किया जा रहा है, या इस मामले में, बस एक में डाल दिया जा रहा है HashSet।

इस कोड का आउटपुट है:

true
false

क्या हुआ है कि जब यह डाला गया हैशकोड का उपयोग किया गया है, जहां वस्तु हैश में है। हैशकोड की गणना करने के लिए उपयोग किए जाने वाले मानों को बदलना हैश को ही पुनः स्थापित नहीं करता है। यह किसी भी परिवर्तनशील वस्तु को हैश की कुंजी के रूप में रखने का खतरा है ।

इस प्रकार, प्रश्न के मूल पहलू पर वापस जा रहा है, कहा जा रहा है विधि "पता नहीं" है कि यह एक पैरामीटर के रूप में कैसे प्राप्त हो रहा है वस्तु का उपयोग किया जा रहा है। "ऑब्जेक्ट को उत्परिवर्तित करने देता है" के रूप में एकमात्र तरीका यह करने का अर्थ है कि इसमें कई सूक्ष्म कीड़े हैं जो रेंग सकते हैं, जैसे कि हैश में मूल्यों को खोना ... जब तक कि आप अधिक नहीं जोड़ते हैं और हैश को फिर से जोड़ दिया जाता है - मेरा विश्वास करो। " , शिकार करने के लिए एक बुरा बग, (मैं मूल्य खो दिया है जब तक कि मैं हैशपॉइंट में 20 और आइटम नहीं जोड़ता हूं और फिर अचानक यह फिर से दिखाता है)।

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

संबंधित: यदि एक कथन के अंदर, कथन के सशर्त के रूप में उपयोग किए गए तर्क को अधिलेखित और वापस लौटाया जाता है


3
यह सही नहीं लगता। सबसे अधिक संभावना predictPriceसीधे Itemसदस्यों के साथ बेला नहीं होनी चाहिए , लेकिन Itemऐसा करने के तरीके के साथ गलत क्या है ? यदि वह एकमात्र वस्तु संशोधित की जा रही है, तो शायद आप एक तर्क दे सकते हैं कि यह वस्तु के संशोधित होने का एक तरीका होना चाहिए, लेकिन कई बार कई वस्तुओं (जो निश्चित रूप से एक ही वर्ग का नहीं होना चाहिए) को संशोधित किया जा रहा है, विशेष रूप से बल्कि उच्च-स्तरीय विधियाँ।

@delnan मैं स्वीकार करूंगा कि यह बग पर एक (ओवर) प्रतिक्रिया हो सकती है जिसे मुझे एक बार एक हैश में गायब और फिर से दिखाई देने वाले मूल्य पर एक बार ट्रैक करना पड़ा था - किसी को सम्मिलित किए जाने के बाद हैश में ऑब्जेक्ट के फ़ील्ड्स के साथ फ़िडलिंग किया गया था इसके उपयोग के लिए वस्तु की प्रति बनाने के बजाय। रक्षात्मक प्रोग्रामिंग उपाय हैं जो कोई भी ले सकता है (जैसे अपरिवर्तनीय वस्तुएं) - लेकिन ऑब्जेक्ट में पुनर्संयोजन मूल्यों जैसी चीजें जब आप ऑब्जेक्ट के "स्वामी" नहीं होते हैं, और न ही वस्तु ही ऐसी चीज है जो आसानी से काटने के लिए वापस आ सकती है तुम मजबूत हो।

आप जानते हैं, एन्कैप्सुलेशन बढ़ाने के लिए क्लास-फ़ंक्शंस के बजाय अधिक फ़ंक्शंस का उपयोग करने के लिए एक अच्छा तर्क है। स्वाभाविक रूप से, एक फ़ंक्शन को एक निरंतर ऑब्जेक्ट मिल रहा है (चाहे इस या एक पैरामीटर के रूप में) इसे किसी भी अवलोकन योग्य तरीके से नहीं बदलना चाहिए (कुछ निरंतर ऑब्जेक्ट चीजों को कैश कर सकते हैं)।
डेडुप्लिकेटर

2

मैं हमेशा किसी और की वस्तु को न बदलने की प्रथा का पालन करता हूं । यह कहना है, केवल वर्ग / संरचना / Whathaveyou के स्वामित्व वाली वस्तुओं को बदलना जो आपके अंदर हैं।

निम्नलिखित डेटा वर्ग को देखते हुए:

class Item {
    public double price = 0;
}

यह ठीक है:

class Foo {
    private Item bar = new Item();

    public void predictPrice() {
        bar.price = bar.price + 5; // or something
    }
}

// Elsewhere...

Foo foo = Foo();
foo.predictPrice();
System.out.println(foo.bar.price);
// Since I called predictPrice on Foo, which takes and returns nothing, it's
// apparent something might've changed

और यह बहुत स्पष्ट है:

class Foo {
    private Item bar = new Item();
}
class Baz {
    public double predictPrice(Item item) {
        return item.price + 5; // or something
    }
}

// Elsewhere...

Foo foo = Foo();
Baz baz = Baz();
foo.bar.price = baz.predictPrice(foo.bar);
System.out.println(foo.bar.price);
// Since I explicitly set foo.bar.price to the return value of predictPrice, it's
// obvious foo.bar.price might've changed

लेकिन यह मेरे स्वाद के लिए बहुत ही मैला और रहस्यमय है:

class Foo {
    private Item bar = new Item();
}
class Baz {
    public void predictPrice(Item item) {
        item.price = item.price + 5; // or something
    }
}

// Elsewhere...

Foo foo = Foo();
Baz baz = Baz();
baz.predictPrice(foo.bar);
System.out.println(foo.bar.price);
// In my head, it doesn't appear that to foo, bar, or price changed. It seems to
// me that, if anything, I've placed a predicted price into baz that's based on
// the value of foo.bar.price

कृपया किसी टिप्पणी के साथ किसी भी डाउनवोट का साथ दें ताकि मुझे पता हो कि भविष्य में बेहतर उत्तर कैसे लिखना है :)
बेन लेगिएरियो

1

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

जावा में, Itemएक संदर्भ प्रकार है - यह उन वस्तुओं को इंगित करता है जो उदाहरण हैं Item। C ++ में, इस प्रकार के रूप में लिखा जाता है Item *(समान चीज़ के लिए सिंटैक्स भाषाओं के बीच भिन्न होता है)। तो Item predictPrice(Item item)जावा Item *predictPrice(Item *item)में C ++ के बराबर है । दोनों मामलों में, यह एक फ़ंक्शन (या विधि) है जो किसी ऑब्जेक्ट के लिए एक पॉइंटर लेता है, और एक ऑब्जेक्ट को पॉइंटर लौटाता है।

C ++ में, Item(बिना कुछ और) एक ऑब्जेक्ट प्रकार है (मान Itemलेना एक वर्ग का नाम है)। इस प्रकार का एक मान "एक वस्तु" है, और Item predictPrice(Item item)एक फ़ंक्शन की घोषणा करता है जो एक वस्तु लेता है और एक वस्तु लौटाता है। चूंकि &इसका उपयोग नहीं किया जाता है, इसलिए इसे पारित किया जाता है और मूल्य द्वारा वापस किया जाता है। इसका मतलब है कि ऑब्जेक्ट को कॉपी किया जाता है जब पास किया जाता है, और वापस लौटने पर कॉपी किया जाता है। जावा में कोई समकक्ष नहीं है क्योंकि जावा में ऑब्जेक्ट प्रकार नहीं हैं।

तो यह कौन सा है? प्रश्न में पूछी गई बहुत सी चीजें (जैसे "मेरा मानना ​​है कि जैसे यह उसी वस्तु पर काम करता है जो ... में पारित हो जाती है") ठीक उसी तरह से समझने पर निर्भर करती है कि क्या पारित किया जा रहा है और यहाँ लौटा दिया गया है।


1

जिस कन्वेंशन को मैंने कोडबेस देखा है, वह ऐसी शैली को पसंद करना है जो वाक्य रचना से स्पष्ट हो। यदि फ़ंक्शन मान बदलता है, तो पॉइंटर द्वारा पास पसंद करें

void predictPrice(Item * const item);

इस शैली के परिणाम:

  • इसे आप देख रहे हैं:

    predictPrice (और my_item);

और आप जानते हैं कि यह शैली में आपके पालन द्वारा संशोधित किया जाएगा।

  • अन्यथा जब आप फ़ंक्शन को संशोधित करने के लिए फ़ंक्शन नहीं चाहते हैं तो कॉन्स्ट रेफरी या मान से पास पसंद करें।

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

0

हालांकि, मेरे पास कोई मजबूत प्राथमिकता नहीं है, मैं वोट करूंगा कि ऑब्जेक्ट को वापस करने से एपीआई के लिए बेहतर लचीलापन होता है।

ध्यान दें कि इसका अर्थ केवल तभी है जबकि विधि में अन्य वस्तु को वापस करने की स्वतंत्रता है। अगर आपका जवादोक कहता है @returns the same value of parameter aतो यह बेकार है। लेकिन अगर आपका जावाडॉक कहता है @return an instance that holds the same data than parameter a, तो उसी उदाहरण या किसी अन्य को वापस करना एक कार्यान्वयन विवरण है।

उदाहरण के लिए, मेरी वर्तमान परियोजना (जावा ईई) में मेरे पास एक व्यावसायिक परत है; डीबी में स्टोर करने के लिए (और एक स्वचालित आईडी असाइन करें) एक कर्मचारी, कहते हैं, एक कर्मचारी मुझे कुछ पसंद है

 public Employee createEmployee(Employee employeeData) {
   this.entityManager.persist(employeeData);
   return this.employeeData;
 }

बेशक, इस कार्यान्वयन के साथ कोई अंतर नहीं है क्योंकि JPA Id असाइन करने के बाद उसी ऑब्जेक्ट को लौटाता है। अब, अगर मैं जेडीबीसी में बदल गया

 public Employee createEmployee(Employee employeeData) {
   PreparedStatement ps = this.connection.prepareStatement("INSERT INTO EMPLOYEE(name, surname, data) VALUES(?, ?, ?)");
   ... // set parameters
   ps.execute();
   int id = getIdFromGeneratedKeys(ps);
   ??????
 }

अब में ????? मेरे पास तीन विकल्प हैं।

  1. आईडी के लिए एक सेट को परिभाषित करें, और मैं उसी वस्तु को वापस करूंगा। बदसूरत, क्योंकिsetId हर जगह उपलब्ध होगा।

  2. कुछ भारी प्रतिबिंब काम करते हैं और आईडी को अंदर सेट करते हैं Employee ऑब्जेक्ट । गंदा, लेकिन कम से कम यह createEmployeeरिकॉर्ड तक सीमित है ।

  3. एक निर्माता प्रदान करें जो मूल की प्रतिलिपि बनाता है Employee और idसेट करने के लिए भी स्वीकार करता है ।

  4. डीबी से ऑब्जेक्ट को पुनः प्राप्त करें (हो सकता है कि अगर डीबी में कुछ फ़ील्ड मानों की गणना की जाती है, या यदि आप एक रियलिटीशिप को पॉप्युलेट करना चाहते हैं)।

अब, 1. और 2. के लिए आप एक ही उदाहरण लौटा सकते हैं, लेकिन 3. और 4. के लिए आप नए उदाहरण लौटाएंगे। यदि प्रिंसिपल से आप अपने एपीआई में स्थापित करते हैं कि "वास्तविक" मूल्य विधि द्वारा वापस आ जाएगा, तो आपके पास अधिक स्वतंत्रता है।

एकमात्र वास्तविक तर्क जो मैं सोच सकता हूं, वह यह है कि, कार्यान्वयन 1 / या 2 का उपयोग करते हुए, आपके एपीआई का उपयोग करने वाले लोग परिणाम के असाइनमेंट की अनदेखी कर सकते हैं और यदि आप 3. या 4. कार्यान्वयन पर बदल जाते हैं तो उनका कोड टूट जाएगा।

वैसे भी, जैसा कि आप देख सकते हैं, मेरी प्राथमिकता अन्य व्यक्तिगत प्राथमिकताओं में आधारित है (जैसे Ids के लिए एक सेटर की मनाही), इसलिए शायद यह सभी के लिए लागू नहीं होगा।


0

जब जावा में कोडिंग होती है, तो एक को दो प्रकारों में से किसी एक के परस्पर परिवर्तनशील प्रकार की प्रत्येक वस्तु के उपयोग का प्रयास करना चाहिए:

  1. वास्तव में एक इकाई को उत्परिवर्तित वस्तु का "स्वामी" माना जाता है और उस वस्तु की स्थिति को अपने हिस्से के रूप में मानता है। अन्य संस्थाएँ संदर्भ रख सकती हैं, लेकिन संदर्भ को किसी ऐसी वस्तु की पहचान के रूप में मानना ​​चाहिए, जिस पर किसी और का स्वामित्व हो।

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

मुझे अंतर्निहित ऑब्जेक्ट को म्यूट करने और संदर्भ वापस करने के तरीके पसंद नहीं हैं, क्योंकि वे ऊपर दिए गए दूसरे पैटर्न को फिट करने की उपस्थिति देते हैं। कुछ मामले हैं जहां दृष्टिकोण सहायक हो सकता है, लेकिन कोड जो वस्तुओं को म्यूट करने जा रहा है , उसे यह देखना चाहिए कि ऐसा करने जा रहा है; कोड की तुलना में myThing = myThing.xyz(q);यह बहुत कम लग रहा है जैसे यह myThingकेवल द्वारा पहचाने गए ऑब्जेक्ट को बदल देता है myThing.xyz(q);

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